Laravel Tutorials

Pause All Laravel Queues During a Deploy

Published
Pause All Laravel Queues During a Deploy image

There is a window during most deploys where the code on disk has changed but the workers running against it have not restarted yet. A worker that reserves a job in that window deserializes a payload written by the old code and runs it through the new code. Most of the time nothing happens. Occasionally a renamed job class or a changed constructor signature turns it into a failed job you have to replay by hand.

The usual workaround is maintenance mode, which stops far more than the queue, or queue:restart, which is a request rather than a guarantee since a worker only sees it between jobs. Laravel 13.25 adds a third option: a switch that stops every worker on every connection from reserving new work, without touching HTTP traffic.

The Command

php artisan queue:pause --all

And to undo it:

php artisan queue:resume --all

The queue argument on both commands is now optional, so --all is the only thing you pass. Without the flag they behave as before and take a connection:queue pair.

The same switch is on the Queue facade for deploy scripts written in PHP, or for a controller behind an admin panel:

use Illuminate\Support\Facades\Queue;
 
Queue::pauseAll();
 
// ...
 
Queue::resumeAll();

What Pausing Actually Does

A paused queue stops workers from reserving new jobs. The worker process stays alive and keeps looping, it just sleeps instead of popping. A job already being processed when you pause runs to completion, so a queue:pause --all in a deploy script does not interrupt anything mid-flight. Producers are unaffected too: SomeJob::dispatch() keeps writing to Redis or the database, and those jobs sit there until you resume.

Mechanically it is one cache key, illuminate:queues:paused, written with forever(). Workers already read the cache once per loop to check for restart and per-queue pause signals, and the global key is fetched in the same many() call, so this adds no extra round trips. QueueManager::isPaused() and getPausedQueues() both report a queue as paused when either the global key or its own key is set.

The Two Switches Are Independent

pause() and pauseAll() write different keys, and they are deliberately not aware of each other. If a queue was paused individually, resumeAll() leaves it paused:

Queue::pause('redis', 'imports'); // parked while we investigate a bad job
 
Queue::pauseAll(); // deploy starts
Queue::resumeAll(); // deploy finishes
 
Queue::isPaused('redis', 'imports'); // true

This is the behavior you want in a deploy script. Somebody parked the imports queue on purpose an hour ago, and a deploy running resumeAll() should not quietly undo that. Clearing an individual pause still takes queue:resume redis:imports.

Events

Two events fire alongside the existing per-queue QueuePaused and QueueResumed:

use Illuminate\Queue\Events\QueuesPaused;
use Illuminate\Queue\Events\QueuesResumed;
 
Event::listen(function (QueuesPaused $event) {
Log::warning('All queues paused');
});

Further Reading

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Sponsored

serpapi logo
SerpApi

The Web Search API for Your LLM and AI Applications

Visit SerpApi

The latest

View all →
Taylor disabled GitHub Issues on most Laravel open-source packages. image

Taylor disabled GitHub Issues on most Laravel open-source packages.

Read article
Exclude Vendor and Default Commands in `php artisan dev` image

Exclude Vendor and Default Commands in `php artisan dev`

Read article
The Laracon Archive image

The Laracon Archive

Read article
Group Adjacent Collection Items in Laravel with chunkBy() image

Group Adjacent Collection Items in Laravel with chunkBy()

Read article
Laravel queue:work Now Prints Why the Worker Stopped image

Laravel queue:work Now Prints Why the Worker Stopped

Read article
Sidecar Brings Statamic's Control Panel to Your Existing Markdown Sites image

Sidecar Brings Statamic's Control Panel to Your Existing Markdown Sites

Read article