neophp/queue-package

Simple database-backed job queue for NeoPHP, processed via a batch worker command

Maintainers

Package info

github.com/NeoPHP-Dev/neo-queue-package

pkg:composer/neophp/queue-package

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.3.1 2026-08-16 09:19 UTC

This package is auto-updated.

Last update: 2026-08-16 09:19:40 UTC


README

A simple, database-backed job queue for NeoPHP. Push jobs, process them in batches via a worker command triggered by a system cron — no long-running process, no external dependency like Redis or a message broker.

Structure

queue-package/
├── composer.json
├── README.md
├── src/
│   ├── NeoQueuePackage.php
│   ├── Command/
│   │   ├── QueueWorkCommand.php
│   │   ├── QueueRetryCommand.php
│   │   └── MakeJobCommand.php
│   ├── Service/
│   │   └── QueueManager.php
│   └── Interface/
│       └── JobInterface.php
└── database/
    ├── Entity/
    │   └── QueueJob.php
    ├── Repository/
    │   └── QueueJobRepository.php
    └── Migrations/
        └── MigrationVersion_Queue_1.php

How it works

Jobs are stored as rows in neo_queue_jobs — no long-running worker process, no Supervisor/systemd setup required. Instead, a system cron calls queue:work on a schedule (typically every minute); each run picks up a batch of due jobs, processes them, and exits.

* * * * * php /path/to/bin/neo queue:work --project=MyProject >> /dev/null 2>&1

If a job throws, it's automatically retried with exponential backoff (1 minute, then 5 minutes) up to 3 attempts total, after which it's marked permanently failed and left for manual inspection.

Installation

php bin/neo package:require neophp/queue-package --project=MyProject

Register it in the project's Config/app.config.php:

return [
    // ...
    'packages' => [
        \Vendor\NeoPHP\QueuePackage\NeoQueuePackage::class,
    ],
];

Run the migration:

php bin/neo database:migration:migrate --project=MyProject

Creating a job

php bin/neo make:job SendWelcomeEmail --project=MyProject

Generates src/MyProject/App/Job/SendWelcomeEmailJob.php:

<?php

declare(strict_types=1);

namespace Neo\Src\MyProject\App\Job;

use Vendor\NeoPHP\QueuePackage\Interface\JobInterface;

final class SendWelcomeEmailJob implements JobInterface
{
    public function __construct(private readonly int $userId)
    {
    }

    public function handle(): void
    {
        // your logic here — e.g. resolve the user and send an email
    }
}

Keep job constructor parameters simple (scalars, IDs) rather than storing whole entity objects — a job may sit in the queue for a while before being processed, so a stale entity reference (deleted row, detached object) is a real risk. Re-fetch what you need inside handle().

Pushing a job

public function register(Request $request, QueueManager $queue): Response
{
    // ...
    $queue->push(new SendWelcomeEmailJob($user->getId()));

    // with an explicit queue name and priority (higher runs first)
    $queue->push(new SendWelcomeEmailJob($user->getId()), queue: 'emails', priority: 10);

    // ...
}

Processing jobs

php bin/neo queue:work --project=MyProject
Option Default Purpose
--queue default Which queue to process
--limit 50 Maximum jobs processed in this run

Each invocation processes what's currently due, then exits — safe to run every minute via cron even if the previous run is still finishing, since each job is marked processing immediately and won't be picked up twice.

Retrying permanently failed jobs

php bin/neo queue:retry --project=MyProject

Resets every job in the failed state back to pending with a fresh attempt count, so the next queue:work run picks them up again. There is currently no way to inspect why a job failed other than querying neo_queue_jobs.last_error directly — no CLI/UI listing is provided in this version.

QueueManager API

Method Purpose
push(JobInterface $job, string $queue = 'default', int $priority = 0): void Enqueue a job
work(string $queue = 'default', int $limit = 50): array{processed, succeeded, failed} Process a batch of due jobs
retryFailed(): int Reset all failed jobs to pending, returns count
stats(): array{pending, processing, done, failed} Current job counts by status

Known limitations

  • No true concurrency protection. If two queue:work processes run at the exact same moment (e.g. a slow run overlapping with the next cron tick), there's a small race window between reading due jobs and marking them processing — acceptable for most use cases, but not suitable for jobs that absolutely cannot run twice without a database-level lock, which this package does not implement.
  • Jobs are serialized with PHP's native serialize(). If you change a job class's constructor signature or namespace after jobs referencing it are already queued, those pending jobs will fail to unserialize. Keep queues empty during deployments that rename or restructure job classes.
  • No priority across queues — priority only orders jobs within the same queue name, not between different queues.
  • No dashboard/UI — inspect job status directly via SQL or build your own admin page using QueueJobRepository.

License

MIT