Pausing and resuming Laravel Jobs cleanly during a deployment is the difference between a calm release and a Slack channel full of 2 AM pings. Workers should stop grabbing new work the moment your code shifts underneath them, but anything already mid-flight should be allowed to finish. Laravel's built-in pause/resume API does exactly that, and in 2026 it's the most surgical way to deploy without touching HTTP traffic. This guide walks through the commands, the cache mechanism behind them, the trade-offs versus queue:restart, and the persona-by-persona playbook for choosing the right strategy.
Definition: A queue pause is a state in which workers are prevented from reserving new jobs from a queue, while jobs already in execution are allowed to run to completion.
How to Pause and Resume Laravel Jobs Safely
Laravel exposes pause and resume through two Artisan commands and a matching Queue facade. Internally, the framework writes a single cache key, illuminate:queues:paused, using a forever() write so it never expires on its own. Workers consult that key before reserving the next job, so the moment the key appears, no new work starts.
Understanding the queue lifecycle
Every Laravel job passes through three observable states: waiting, reserved, and completed (or failed). The pause flag only intercepts the waiting-to-reserved transition. A worker that has already reserved a job runs it to the end, the retry backoff, or its timeout. Understanding this boundary is what makes pause predictable in production.
Using Artisan queue:pause and queue:resume
From the command line, you can pause everything with php artisan queue:pause --all or target a single connection and queue, such as php artisan queue:pause redis imports. Resume mirrors the syntax: php artisan queue:resume --all or php artisan queue:resume redis imports. The same calls exist programmatically through the Queue facade, Queue::pauseAll() and Queue::resume('redis', 'imports'), which is useful inside deploy scripts or health checks.
Monitoring paused state with Horizon
Horizon reads the same cache key, so the dashboard reflects the paused state as soon as the command runs. Supervisors that need richer observability can subscribe to the QueuesPaused and QueuesResumed events, or rely on packages like Watchtower for unified visibility across multiple queue drivers.
Why Queue Control Matters in 2026 Deployments
Releases are no longer "stop the world" events. Modern Laravel shops ship multiple times per day, and queue control is the lever that keeps asynchronous work aligned with the code that's currently running.
Impact on zero-downtime releases
Pausing jobs before swapping code prevents a class of subtle bugs where a worker still running the old binary picks up a job that was serialized against the new schema. Resume only after the new workers are warm, and you keep the contract between producer and consumer consistent.
Relation to CI/CD pipelines
Pipelines that run php artisan queue:pause --all as a pre-deploy step and queue:resume --all as a post-deploy step treat queue state as a first-class artifact. This pairs well with blue/green or rolling strategies on Amazon ECS where old tasks drain and new tasks come online.
User experience implications
HTTP requests stay live while you deploy, but background side effects (emails, exports, payment confirmations) are deferred by exactly the duration of your deploy. For most products that is invisible. For long-running image pipelines, planning the pause window is part of the SLA.
Prerequisites for Queue Management in Laravel
Before relying on pause/resume, your environment needs to meet a small set of non-negotiable prerequisites. Skip any one of these and the pause becomes a polite suggestion rather than a guarantee.
Laravel version requirements
Native pause/resume shipped in Laravel 10 and matured through 11 and 12, with 13.x (including 13.14.0, 13.25, 13.8.0 and 13.7.0) extending it with the Interruptible interface, WorkerInterrupted event, and bulk inspection helpers like Queue::pendingJobs(). The features covered in this guide assume Laravel 12 or 13 on PHP 8.2 or newer.
Cache driver configuration
The pause flag lives in the cache store your queue driver uses by default. For a single-region Redis setup, point all workers at the same connection. For a multi-cluster setup, ensure the cache store is shared; otherwise one cluster will pause while another keeps chewing through jobs.
Required IAM or service permissions
If your workers run on AWS Batch, ECS, or Fargate, the underlying task role needs permission to read and write the configured cache (for example, Amazon ElastiCache for Redis or Amazon DynamoDB). For Amazon SQS, the pause flag is local to the application cache; jobs are merely held at the worker layer.
Step-by-Step: Pausing Queues with Artisan Commands
Here is the shortest reliable sequence for pausing queues around a deploy, including the verification step that catches the most common mistake.
Executing queue:pause
Run php artisan queue:pause --all from your deploy script right before the new build replaces the old one. The command returns instantly, but it is worth waiting a few seconds (or polling the cache) to confirm workers have observed the flag.
Verifying the pause flag in cache
Check the key directly with php artisan tinker or your cache CLI:
Cache::get('illuminate:queues:paused');
// expected output: the pause payload, e.g. {"redis:default":true,"redis:imports":true}
If the key is missing, the cache store your workers actually use is not the one you think it is. This is the single most common source of "the pause didn't work" tickets.
Resuming with queue:resume
After the new code is live and healthy, run php artisan queue:resume --all. For programmatic control from a health-check callback, use Queue::resumeAll();. Remember that resumeAll() only lifts a global pause; queues paused individually must be resumed by name.
Alternative Approach: Using queue:restart and Idempotent Jobs
Some teams prefer a simpler model: tell every worker to exit after its current job, then let the supervisor relaunch them against the new code. This is queue:restart, and it works well when your jobs are idempotent.
When to prefer queue:restart
For small teams that don't want to operate a shared cache just to coordinate deploys, php artisan queue:restart is enough. The supervisor (Horizon, systemd, Kubernetes, ECS) respawns the worker, which then loads the freshly deployed code. There is no coordination overhead beyond a signal file.
Designing idempotent job payloads
Idempotency is what makes restart safe. A job that always re-checks "did the side effect already happen?" can be retried, replayed, or restarted without duplication. Use a unique key per business action and store the result before performing it.
Comparing downtime characteristics
Restart only triggers between jobs. If a worker is mid-job when the signal arrives, it finishes first. That means queue:restart has a tail latency equal to your longest job, while pause stops new reservations immediately. For a Stripe-backed payments flow with seconds-long jobs, the difference is negligible. For a video transcode measured in minutes, the difference is your entire deploy window.
Trade-offs: Pause vs. Restart in Production
Both methods solve the same problem at different layers. Pause adds a coordination cache and a soft handoff; restart adds a hard handoff and depends on idempotency. The right answer depends on your topology and your job shapes.
Cache consistency across clusters
Pause relies on a single cache key being visible to all workers. In a Redis cluster with eventual consistency, a worker on a stale replica may keep reserving for a few seconds. Restart has no such dependency: each worker is killed individually, so there's no shared state to converge.
Effect on in-flight jobs
Neither method aborts an in-flight job. Pause lets it finish naturally. Restart lets it finish, then the new worker picks up a fresh copy. If you need true mid-job cancellation, look at the Interruptible interface introduced in Laravel 13.7.0, which lets a job implement interrupted(int $signal) and listen to the WorkerInterrupted event.
Performance impact on high-throughput queues
Pause adds a single cache read per job reservation, which on Redis is sub-millisecond. Restart adds zero overhead per job but pays the cost of process churn. On a high-throughput queue, pause is cheaper; on a low-throughput queue with heavy jobs, restart is fine.
Pros, Cons, and Best Practices for Zero-Downtime Deployments
Use this section as a checklist before you wire pause into production. The list below is intentionally opinionated, based on real-world patterns from teams running Laravel Jobs at scale.
Pros of pause: precise control
Pause stops new reservations at the exact moment the cache key flips, leaving HTTP traffic and in-flight jobs alone. It is independent per connection and per queue, so you can isolate high-risk migrations while letting the rest of the system flow.
Cons of pause: cache single point of failure
If your cache is down, pause silently fails open (workers keep reserving) or fails closed (everything stops). Neither is what you want during a deploy. Run a health check on the cache before issuing the pause command.
Best practice checklist
- Pause before code swap, resume after new workers pass readiness checks.
- Use a dedicated cache store (not the default file cache) for the pause key.
- Make jobs idempotent regardless, so resume never produces duplicates.
- Subscribe to
QueuesPausedandQueuesResumedfor audit logs and Slack alerts. - Test the full pause/resume cycle in staging with a synthetic load test.
- Combine pause with a graceful SIGTERM handler in long-running jobs.
Common Mistakes and How to Troubleshoot Queue Pauses
Most "the pause didn't work" reports trace back to one of a handful of misconfigurations. Walk through this list before reaching for a debugger.
Forgot to clear compiled views
Stale compiled Blade views and cached configs can make a worker believe the cache store is different from the one your CLI used. Run php artisan optimize:clear as part of your pre-deploy ritual.
Misinterpreting paused state in logs
Workers that have already reserved a job will not log "paused" until they finish and try to reserve again. A quiet log is not a broken pause. Use Queue::pendingJobs(), Queue::reservedJobs(), and Queue::delayedJobs() from Laravel 13.4.0 to inspect the real state.
Race conditions with code deployment
If you resume before the new code is fully loaded by your workers, you can get a mixed state where old code handles the next job. Sequence matters: code deploy first, then resume, with a health-check gate in between.
Who Should Use Pause vs. Restart? Persona Mapping Table
Different teams need different things from queue control. The table below maps common personas to the strategy that fits their reality.
| Target Persona | Recommended Option | Key Reason & Real-World Benefit |
|---|---|---|
| Small development teams (1–5 devs) | queue:restart with idempotent jobs |
No shared cache to operate, fewer moving parts, and restart signals ride the existing supervisor. A solo founder shipping twice a day gets the same zero-downtime result without running Redis. |
| Enterprise CI/CD pipelines | queue:pause --all + queue:resume --all wired into the pipeline |
Pause gives a deterministic, observable state transition in the pipeline log, which auditors and SREs both love. It composes cleanly with blue/green on ECS or Fargate. |
| Multi-tenant SaaS platforms | Per-queue queue:pause redis tenant-imports |
You can pause a single tenant's heavy import without freezing the other 10,000 tenants. This surgical control is what makes pause worth the cache dependency. |