oeltimacreation / php-simplequeue
A lightweight, framework-agnostic background job queue system for PHP with Redis and database drivers
Package info
github.com/oeltimacreation/php-simplequeue
pkg:composer/oeltimacreation/php-simplequeue
Requires
- php: ^8.2
- psr/container: ^1.1|^2.0
- psr/log: ^2.0|^3.0
Requires (Dev)
- dealerdirect/phpcodesniffer-composer-installer: ^1.2
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.2.2
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^11.0
- predis/predis: ^3.0
- slevomat/coding-standard: ^8.29
- squizlabs/php_codesniffer: ^4.0
Suggests
- ext-pcntl: Required for graceful worker shutdown on Unix systems
- ext-pdo: Required for database queue driver
- predis/predis: Required for Redis queue driver (^3.0)
This package is auto-updated.
Last update: 2026-08-01 02:23:08 UTC
README
A small, framework-agnostic PHP queue for durable background jobs. Job data is stored in a database; Redis or database polling delivers work to workers.
It supports retries with backoff, delayed retries, scheduled first dispatch, progress reporting, lease-based job ownership, graceful shutdown, and bounded queue repair.
Requirements
- PHP 8.2 or later
- PDO and a supported database for durable jobs
- Redis 7+ or Valkey 8+ with
predis/predis:^3for Redis delivery (optional)
Install
composer require oeltimacreation/php-simplequeue
composer require predis/predis # only when using the Redis driver
Create the background_jobs table using the schema for your database in
the database guide.
Quick start
The in-memory sample has no services to configure and is the fastest way to see the complete dispatch → process → inspect flow:
php examples/basic/in-memory.php
For a durable Redis setup, configure the environment variables shown in the Redis example, then run the worker and dispatcher in separate terminals.
use Oeltima\SimpleQueue\Contract\JobHandlerInterface; use Oeltima\SimpleQueue\Driver\InMemoryQueueDriver; use Oeltima\SimpleQueue\JobDispatcher; use Oeltima\SimpleQueue\JobRegistry; use Oeltima\SimpleQueue\QueueManager; use Oeltima\SimpleQueue\Storage\InMemoryJobStorage; use Oeltima\SimpleQueue\Worker; final class WelcomeEmail implements JobHandlerInterface { public function handle(int $jobId, array $payload, ?callable $progress = null): mixed { if ($progress !== null) { $progress(100, 'Email sent'); } return ['recipient' => $payload['email']]; } } $storage = new InMemoryJobStorage(); $queues = new QueueManager(new InMemoryQueueDriver()); $registry = new JobRegistry(); $registry->register('email.welcome', WelcomeEmail::class); $dispatcher = new JobDispatcher($storage, $queues); $jobId = $dispatcher->dispatch('email.welcome', ['email' => 'ada@example.test']); (new Worker($storage, $queues, $registry, queue: 'default', options: ['lock_file' => null]))->processOne(); echo $dispatcher->getStatus($jobId)?->status->value; // completed
Scheduled dispatch
Delay a job's first availability with dispatchAfter(), dispatchAt(), or the
optional $availableAt parameter on dispatch() / dispatchBatch():
$jobId = $dispatcher->dispatchAfter(300, 'email.welcome', ['email' => 'ada@example.test']); $jobId = $dispatcher->dispatch( 'email.welcome', ['email' => 'ada@example.test'], availableAt: strtotime('tomorrow 09:00'), );
Past or present timestamps dispatch immediately; non-positive timestamps and
negative delays are rejected. With Redis/In-Memory the notification is delayed
and promoted when due; with database polling claims already gate on the stored
available_at.
Documentation
- Getting started — durable setup and first worker
- Configuration — drivers and worker options
- Database guide — schemas, indexes, and idempotency
- Operations — deployment, repair, retention, monitoring
- Architecture — delivery and ownership model
- Extending — custom handlers, storage, and drivers
- Upgrading — supported upgrade paths
- Examples — runnable sample catalogue
Important delivery rule
SimpleQueue provides at-least-once delivery. A job can run more than once if a worker completes a side effect and stops before its acknowledgement is stored. Make every handler idempotent: use transaction IDs, unique database constraints, or provider idempotency keys for external side effects.
dispatchIdempotent() prevents duplicate active jobs for one request ID.
For cross-process safety with PdoJobStorage, keep the conditional/generated
active-request-ID unique index from the database guide.
Development
composer check # tests, PHPStan, and coding style composer test composer phpstan composer cs-check composer test-coverage
See CONTRIBUTING.md for contribution details, SECURITY.md for vulnerability reporting, and LICENSE for license terms.