Skip to content

Quick Start

Muhammet Şafak edited this page Jun 9, 2026 · 1 revision

Quick Start

This walkthrough takes you from nothing to a producer pushing messages and a worker consuming them. It uses the PDO transport so you need no broker — just a database (SQLite here).

1. Write a handler

A handler implements InitPHP\Queue\Contracts\Handler and is mapped to a message URN. It receives a read-only BabelQueue\Contracts\InboundMessage. Return to acknowledge; throw to fail (the worker retries, then dead-letters).

useBabelQueue\Contracts\InboundMessage;
useInitPHP\Queue\Contracts\Handler;
finalclass SendWelcomeEmail implements Handler
{
publicfunctionhandle(InboundMessage$message): void
{
$data = $message->getData(); // ['user_id' => 42, 'email' => '...']$traceId = $message->getTraceId(); // correlate with the producer$meta = $message->getMeta(); // ['id' => ..., 'queue' => ..., 'lang' => ...]// Do the work. An exception here marks the message as failed.// mailer()->sendWelcome($data['email']);
}
}

Idempotency. Delivery is at-least-once: a handler may run more than once for the same message (after a crash, for example). Make it safe to repeat.

2. Build a transport

useInitPHP\Queue\Transport\Pdo\PdoTransport;
$pdo = newPDO('sqlite:' . __DIR__ . '/queue.sqlite');
$transport = newPdoTransport($pdo, table: 'jobs');
$transport->createSchema(); // creates the jobs / jobs_failed tables (dev convenience)

3. Produce a message

useInitPHP\Queue\Producer\Producer;
$producer = newProducer($transport, defaultQueue: 'emails');
$producer->send('urn:babel:users:registered', [
'user_id' => 42,
'email' => 'jane@example.com',
]);

send() encodes the canonical envelope and publishes it. A consumer in any language subscribed to the emails queue can read it.

4. Consume messages

Map URNs to handlers, wrap them in a Dispatcher, and run a Worker.

useInitPHP\Queue\Consumer\Dispatcher;
useInitPHP\Queue\Consumer\Worker;
useInitPHP\Queue\Consumer\WorkerOptions;
useInitPHP\Queue\Routing\HandlerMap;
$handlers = (newHandlerMap())
->register('urn:babel:users:registered', SendWelcomeEmail::class);
$worker = newWorker(
$transport,
newDispatcher($handlers),
newWorkerOptions(maxAttempts: 3, backoff: [1, 5, 15]),
);
$worker->run('emails'); // loops, processing messages until stopped

To process the queue once and exit (handy in tests or cron):

$worker->runOnce('emails'); // returns bool: was a message processed?

5. Run it as a process

Put the wiring in a bootstrap file that returns a configured Worker, and run it with the CLI:

// worker.phprequire__DIR__ . '/vendor/autoload.php';
useInitPHP\Queue\Consumer\{Dispatcher, Worker, WorkerOptions};
useInitPHP\Queue\Routing\HandlerMap;
useInitPHP\Queue\Transport\Pdo\PdoTransport;
$transport = newPdoTransport(newPDO('sqlite:' . __DIR__ . '/queue.sqlite'), 'jobs');
$handlers = (newHandlerMap())->register('urn:babel:users:registered', SendWelcomeEmail::class);
returnnewWorker($transport, newDispatcher($handlers), newWorkerOptions(maxAttempts: 3));
php vendor/bin/queue work --bootstrap=worker.php --queue=emails
# or process exactly one message and exit:
php vendor/bin/queue work --bootstrap=worker.php --queue=emails --once

Run the worker under a process supervisor (systemd, supervisord, a container restart policy) and set a maxJobs/memoryLimitMb limit so each worker exits and is restarted periodically.

What next?

Clone this wiki locally