Laravel Queue Workers Stalled: How to Diagnose Idle Workers and Restore Job Processing
Laravel queue workers may appear idle, showing "Processing" without completing jobs. This guide outlines symptoms, common causes, step‑by‑step checks, targeted fixes, and escalation criteria to restore job processing.
08 Oct 2025, 19:53 UTC

Recognizable Symptom
Workers display a "Processing" status in the queue monitoring UI or console, yet no jobs transition to "Processed" and the jobs table remains unchanged. This indicates that the worker is alive but unable to claim or finish jobs.
Diagnostic Overview
| Potential Cause | Typical Symptom |
|---|---|
| Queue driver misconfiguration (e.g., Redis down) | Worker shows "Processing" but no job records change. |
| Worker process not running or crashed | No activity in supervisor logs; worker count zero. |
| Database connection loss | Worker logs contain connection errors; jobs stay pending. |
| Job serialization error | Worker logs report "Unable to unserialize job". |
| Timeout/lock contention | Jobs remain in "Waiting" for extended periods. |
Step 1: Confirm the worker process is active
Run the appropriate command for your queue manager. For plain artisan queue:work:
php artisan queue:work --once
Required permission: a user with access to the application directory (often the web‑server user or a developer with sudo rights). Expected output includes a "Processing" line followed by a "Processed" entry when the job finishes. If no output appears, the worker may be stopped.
Step 2: Validate queue driver health
Check the status of the driver you are using. For Redis (the recommended driver in Laravel 10+):
redis-cli ping
Expected response: "PONG". If the command fails or times out, Redis is unavailable and you must restart the service or adjust the QUEUE_CONNECTION value in .env.
For database drivers, inspect the queued_jobs table for locked rows that exceed the default timeout (60 seconds). Use:
SELECT * FROM queued_jobs WHERE locked_until > UNIX_TIMESTAMP();
If many rows are locked, consider increasing the queue_jobs_retry_after setting or tuning the driver’s connection pool.
Step 3: Inspect database and logs
Connect to the database and verify that pending jobs exist:
SELECT id, payload, attempts FROM jobs WHERE status = 'pending';
If the table is empty but the worker still shows "Processing", the issue is likely in the worker’s job‑dispatch logic rather than the queue storage.
Review the worker logs (e.g., horizon status for Horizon, or storage/logs/laravel-queue.log for plain workers). Look for errors such as "Connection could not be established" or "Failed to unserialize job".
Step 4: Review recent code changes for job serialization
Serialization errors often arise after adding new properties to a job class or changing its namespace. Run:
composer dump-autoload
Then re‑run a single job:
php artisan queue:work --once
If the job fails with a "SerializationException", update the job class to implement Illuminate\Contracts\Queue\Queueable correctly and ensure the composer autoloader is up‑to‑date.
Step 5: Check for lock contention and timeout settings
High traffic can cause rows to be locked for longer than the default 60-second timeout, making it appear as if jobs are stuck. Adjust the queue_jobs_retry_after and queue_jobs_timeout values in config/queue.php if you are using the database driver. Example:
'timeout' => 300, // seconds
Increasing the timeout gives jobs more room to finish, but also lengthens the period during which the row is locked. Test the change in a staging environment first.
Fixes Tied to Findings
- Worker missing → Restart the process (e.g.,
systemctl restart horizon) or enable a supervisor such assupervisordto keep it alive. - Driver down → Re‑start the Redis service (
systemctl restart redis) or correct theQUEUE_CONNECTIONenv variable. - Database connection lost → Verify credentials in
.env, test connectivity withphp artisan tinker, and resolve network or firewall issues. - Serialization error → Update the job class, run
composer dump-autoload, and redeploy the code. - Lock contention → Raise the timeout or retry‑after values, or move to a faster driver like Redis for high‑throughput workloads.
Escalation Triggers
If after completing all steps the queue remains empty, no logs show activity, and the worker count is zero, the problem is likely at the infrastructure level. Escalate to the operations team for driver‑level diagnostics (e.g., Redis memory, network partitions) or to the Laravel maintainers if a framework‑specific bug is suspected (check the GitHub issue tracker for the current Laravel version).
Verification
- Run
php artisan queue:work --onceand confirm a "Processed" entry appears in thejobstable. - Check the supervisor log (e.g.,
horizon status) for error messages and verify the worker count matches the expected number. - If using Horizon, open the dashboard and ensure the queue length drops to zero after processing.
Limitations
Database‑backed queues may experience prolonged row locks under heavy load, which can masquerade as stalls. Switching to Redis mitigates this but introduces a separate service to monitor. Laravel 10+ introduced PHP 8.2 compatibility; older PHP versions may cause serialization failures. Always test configuration changes in a non‑production environment before applying them to live workers.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.