Pause and resume queue workers in Laravel

laravel
tutorial
queues
Nabil Hassen
Nabil Hassen
Dec 3, 2025
Pause and resume queue workers in Laravel
Last updated on Dec 3, 2025
Table of contents:

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:

  • database is the connection name.
  • default is the queue name.
  • Any workers processing jobs from database / default will 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:default was paused will start pulling new jobs again from that queue.
  • Jobs that accumulated on database / default while 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 DateTimeInterface instance.
    • A DateInterval instance.

Here is a simple example that pauses a queue for 60 seconds:

use Illuminate\Support\Facades\Queue;
 
// Pause for 60 seconds
Queue::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 now
Queue::pauseFor('redis', 'default', now()->addMinutes(5));

Or using a DateInterval:

use DateInterval;
use Illuminate\Support\Facades\Queue;
 
// Pause for 45 seconds via DateInterval
Queue::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::resume when 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-After header 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::pause or Queue::pauseFor and then resume it with php artisan queue:continue.
  • You can pause with php artisan queue:pause and then resume later from code using Queue::resume.
  • Queue::isPaused reflects 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.

Nabil Hassen
Nabil Hassen
Full Stack Web Developer

Stay Updated.

I'll you email you as soon as new, fresh content is published.

Thanks for subscribing to my blog.

Latest Posts