Enqueueing
push()
$id = $queue->push(new SendEmailJob('user@example.com', 'Welcome'), 'email');
$queue->push(
new SendEmailJob('user@example.com', 'Your trial ends soon'),
'email',
scheduledAt: new DateTimeImmutable('+1 hour'),
expiresAt: new DateTimeImmutable('+1 day'),
);push() encodes the job with the codec, stores it as pending and returns its ID.
| Argument | Default | Effect |
|---|---|---|
type | 'default' | The job's type, up to 64 characters: see Types |
scheduledAt | now | The earliest time the job may run |
expiresAt | null | The deadline after which it no longer runs |
Dates may be in any timezone; the queue stores them in UTC. The queue's retry policy is stored with the job at the same time, so a later change to the queue's configuration does not affect jobs already enqueued.
pushMany()
$jobs = array_map(fn(int $id): ImportRowJob => new ImportRowJob($importId, $id), $rowIds);
$count = $queue->pushMany($jobs, "import-{$importId}");All the jobs share the type, schedule and deadline. They are written in multi-row inserts of up to 1,000 jobs, which keeps each statement under the bound-parameter limits of every database. Each chunk is atomic; if a later chunk fails, the earlier ones stay. The return value is the number of jobs stored. Very large payloads remain subject to the database's packet and statement size limits.
Types
A type partitions the queue:
- a worker or
processJobs($limit, $type)can run one type only, so slow jobs cannot hold up urgent ones; getStats($type)counts one type, which is how you follow a batch.
A unique type per batch gives you its progress for free:
$type = "import-{$importId}";
$queue->pushMany($jobs, $type);
// Later, from a status endpoint:
$stats = $queue->getStats($type);
$finished = $stats['completed'] + $stats['failed'] + $stats['expired'];
$total = $finished + $stats['pending'] + $stats['in_progress'];Order
Ready jobs are claimed in order of scheduled_at, then ID: first in, first out among jobs due at the same time. A retried job is due again after its backoff, so it queues behind jobs that were already due.
In a Transaction
push() and pushMany() may run inside your application's transaction. The job is then stored if and only if your changes commit:
$connection->transactional(function () use ($queue, $order): void {
$this->orders->save($order);
$queue->push(new SendOrderConfirmationJob($order->id), 'email');
});This only holds when the queue and your data share the connection. Consumer operations are different: they require autocommit, so give workers a connection of their own when the application's connection may be inside a transaction.
Logging
With a PSR-3 logger, push() logs Job queued at info with the id, name and type, and pushMany() logs Jobs queued with the count and type.