Pause and resume queue workers in Laravel
- How to pause and resume queue workers in Laravel
- What it means to pause a queue
- Pausing and resuming queues with Artisan
- Pausing and resuming queues programmatically
- Conclusion
How to pause and resume queue workers in Laravel
In this guide, you will learn how to pause and resume Laravel queue workers on demand.
We will work in the context of long running queue:work processes managed from the CLI.
You will see how to target specific connections and queues when pausing workers.
You will also see how to pause queues indefinitely or for a fixed amount of time from both Artisan and application code.
What it means to pause a queue
Before touching any commands, it helps to be precise about what a "paused" queue actually does in Laravel:
- Pausing is per queue and per connection, not global for all queues.
- Workers that are already running finish the job they are currently processing.
- Once the current job finishes, workers stop pulling new jobs from the paused queue.
- The worker process itself keeps running; it does not exit or get killed.
- When the queue is resumed, workers immediately start pulling jobs again from that queue.
So pausing is a way to temporarily put a queue on hold without touching your process manager or worker processes.
Pausing and resuming queues with Artisan
The most direct way to pause and resume queues is via Artisan. This is usually what you will do in production shells or deployment scripts.
Starting a worker for a specific connection and queue
First, assume you have a worker processing a queue. For example:
php artisan queue:work database --queue=default
This worker uses the database queue connection and listens to the default queue.
The connection name comes from config/queue.php, and the queue name is whatever you configured or used when dispatching jobs.
As long as this process is running, it will keep picking up jobs from the database connection's default queue.
Pausing a queue from the CLI
To pause a queue, you use the queue:pause command and pass a single argument in the connection:queue format:
php artisan queue:pause database:default
Key points:
-
databaseis the connection name. -
defaultis the queue name. - Any workers processing jobs from
database/defaultwill finish their current job. - After finishing that job, they will not fetch any new jobs from that queue until it is resumed.
If you are using Redis with a custom queue name, pausing that queue looks like this:
php artisan queue:pause redis:emails
Workers that are listening on redis and processing the emails queue will stop taking new jobs from emails, but can continue to process other queues if they are configured to listen to multiple queues.
Resuming a queue from the CLI
To resume job processing on a paused queue, you use queue:continue with the same connection:queue syntax:
php artisan queue:continue database:default
After this command runs:
- Workers that were idle because
database:defaultwas paused will start pulling new jobs again from that queue. - Jobs that accumulated on
database/defaultwhile it was paused will now be processed as normal.
You can do the same for any other connection and queue combination. For example:
php artisan queue:continue redis:emails
This resume command works regardless of whether the queue was paused via Artisan or via application code, since both go through the same underlying queue manager.
Pausing and resuming queues programmatically
Sometimes you want to pause or resume a queue from your application code instead of the CLI. For example, you might want to pause a queue when an external API rate limit is hit, or when an admin flips a feature flag in a dashboard.
For that, Laravel exposes queue pausing APIs via the Queue facade and the underlying QueueManager class.
Indefinitely pausing a queue in code
To pause a queue indefinitely from code, you can call Queue::pause with a connection and queue name:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request;use Illuminate\Support\Facades\Queue; class QueueAdminController{ public function pauseDefaultDatabaseQueue(Request $request) { // Pause the "default" queue on the "database" connection indefinitely Queue::pause('database', 'default'); return response()->json([ 'status' => 'ok', 'message' => 'database:default queue paused', ]); }}
What matters in this example:
-
Queue::pause('database', 'default')pauses the queue identified by that connection and queue. - The pause is indefinite. The queue stays paused until you explicitly resume it.
- You can call this from anywhere in your app: controllers, commands, services, or jobs.
To resume the same queue from code, call Queue::resume:
Queue::resume('database', 'default');
You can safely call Queue::resume even if the queue is not currently paused. It simply ensures the paused flag is cleared.
Pausing a queue for a fixed amount of time
Laravel also lets you pause a queue for a specific duration using Queue::pauseFor.
This method accepts three arguments:
-
The connection name.
-
The queue name.
-
A TTL (time to live) value that can be:
- An integer number of seconds.
- A
DateTimeInterfaceinstance. - A
DateIntervalinstance.
Here is a simple example that pauses a queue for 60 seconds:
use Illuminate\Support\Facades\Queue; // Pause for 60 secondsQueue::pauseFor('redis', 'default', 60);
You can also express the pause using a DateTimeInterface by giving the exact moment when the pause should expire:
use Illuminate\Support\Facades\Queue; // Pause until five minutes from nowQueue::pauseFor('redis', 'default', now()->addMinutes(5));
Or using a DateInterval:
use DateInterval;use Illuminate\Support\Facades\Queue; // Pause for 45 seconds via DateIntervalQueue::pauseFor('redis', 'default', new DateInterval('PT45S'));
When you use pauseFor:
- Laravel sets an internal flag that marks the queue as paused for the given TTL.
- While the flag is active, workers do not pull new jobs from that queue after finishing what they are currently processing.
- Once the TTL expires, the flag automatically disappears and workers will treat the queue as active again.
- You do not have to call
Queue::resumewhen the TTL expires, although you can still call it manually if you want to resume earlier.
Example: pausing a queue when an external API returns 429
A very practical use case for pauseFor is handling rate limited APIs that return HTTP 429 with a Retry-After header.
Here is a simplified example inside a job that consumes such an API:
<?php namespace App\Jobs; use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Bus\Dispatchable;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Queue\SerializesModels;use Illuminate\Support\Facades\Http;use Illuminate\Support\Facades\Queue; class SyncExternalData implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function handle(): void { $response = Http::get('https://example.com/api/data'); if ($response->status() === 429) { $retryAfter = (int) $response->header('Retry-After', 60); // Pause the queue that is processing this job for the Retry-After period Queue::pauseFor($this->queueConnection(), $this->queueName(), $retryAfter); // Optionally release this job so it can be retried later $this->release($retryAfter); return; } // Normal processing logic for successful responses... } protected function queueConnection(): string { return $this->connection ?? config('queue.default'); } protected function queueName(): string { return $this->queue ?? 'default'; }}
Important details here:
-
Queue::pauseFor(...)is called with the same connection and queue that this job is running on. - The TTL is taken from the
Retry-Afterheader when available, or defaults to 60 seconds. -
release($retryAfter)tells the queue to retry the job after the same delay, so processing resumes when the pause ends. - Other jobs on the same queue will also be paused until the TTL expires.
You can adapt this pattern to any situation where you need to back off a whole queue for a while.
Checking whether a queue is paused
Sometimes you just want to know if a queue is currently paused so you can make a decision in code. For that, you can use Queue::isPaused:
use Illuminate\Support\Facades\Queue; if (Queue::isPaused('redis', 'default')) { // Maybe skip dispatching some jobs or show a warning in the UI}
This method returns true if the queue is paused (either indefinitely or until a future time) and false otherwise.
How CLI and code based pausing work together
The Artisan commands and the Queue facade both use the same underlying queue manager and the same pause state.
That means:
- You can pause a queue from code with
Queue::pauseorQueue::pauseForand then resume it withphp artisan queue:continue. - You can pause with
php artisan queue:pauseand then resume later from code usingQueue::resume. -
Queue::isPausedreflects the state regardless of how the pause was initiated.
Because the pause state is shared, you do not need to worry about different mechanisms conflicting with each other.
Conclusion
You have seen how Laravel lets you pause and resume specific queues without stopping worker processes.
You can control queue pausing from Artisan using queue:pause and queue:continue with a simple connection:queue argument.
You can also pause queues indefinitely or for precise durations in code using the Queue facade, and check the current pause state when needed.
With these tools you can integrate pausing deeply into your workflows, deployments, and rate limiting strategies without touching your worker supervision setup.
Stay Updated.
I'll you email you as soon as new, fresh content is published.