Crashing Laravel Queues on VPS: How I Fixed My PHP‑FPM + Redis “Queue Worker Die” Error and Restored 99.9% Cron Stability in 30 Minutes
If you’ve ever watched a production Laravel queue die in the middle of a heavy‑load night‑shift, you know the panic that follows—missed emails, failed webhooks, and an angry ops team. I spent an entire evening watching the php-fpm master process restart every 5 minutes while Redis kept reporting “OOM command not allowed.” The result? A broken Cron schedule and a crippled API.
php-fpm memory limits + low Redis maxmemory + missing Supervisor config caused the workers to die. A quick systemctl reload php-fpm, redis maxmemory 2G, and a proper Supervisor numprocs setting restored 99.9% uptime in under half an hour.
Why This Matters
The health of your Laravel queue directly impacts business‑critical features: order processing, payment confirmations, and notification delivery. When a queue worker crashes, the backlog grows, MySQL connections spike, and your VPS can quickly run out of RAM, causing a cascade of failures across WordPress sites hosted on the same server.
Common Causes of “Queue Worker Die” Errors
- PHP‑FPM
pm.max_childrenset too high for available RAM. - Redis
maxmemoryleft at the default (256 MB) on a 4 GB VPS. - Supervisor not restarting failed workers (no
autorestart). - Missing
APP_DEBUG=falsein production, which floods logs. - Out‑of‑date Composer autoload causing memory leaks.
Step‑By‑Step Fix Tutorial
1. Diagnose the current PHP‑FPM pool
# cat /etc/php/8.2/fpm/pool.d/www.conf | grep -E 'pm.max_children|pm.start_servers|pm.max_requests'
pm.max_children = 30
pm.start_servers = 6
pm.max_requests = 5000
2. Calculate safe pm.max_children
Assume each Laravel worker uses ~80 MB. On a 4 GB VPS allocate 2 GB for PHP‑FPM:
# echo $((2048 / 80))
25
Set pm.max_children = 25 and reload PHP‑FPM.
3. Tune Redis memory
# redis-cli CONFIG SET maxmemory 2gb
# redis-cli CONFIG SET maxmemory-policy allkeys-lru
4. Configure Supervisor for Laravel workers
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3 --daemon
autostart=true
autorestart=true
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/log/laravel/queue.log
stopwaitsecs=3600
Run supervisorctl reread && supervisorctl update && supervisorctl restart laravel-queue:* to apply.
5. Reduce Laravel log noise
// .env
APP_DEBUG=false
LOG_CHANNEL=stack
LOG_LEVEL=error
6. Verify Cron stability
# crontab -l
* * * * * php /var/www/html/artisan schedule:run >> /dev/null 2>&1
Watch tail -f /var/log/syslog | grep php-fpm for 10 minutes. No “SIGSEGV” entries should appear.
worker died event. Cron ran 1 ,440 times a day with 99.9% success rate.
VPS or Shared Hosting Optimization Tips
- Never run
php artisan config:cacheon a shared host that usesmod_php; it can overwritephp.inioverrides. - Enable
opcache.enable_cli=1for queue workers. - Use
systemctl status redisto ensure the service is set toRestart=alwaysin the systemd unit. - On a low‑end VPS, pin PHP‑FPM to a single core via
taskset -c 0-1to avoid CPU throttling.
Real World Production Example
At Acme SaaS we ran 12 Laravel micro‑services on a single 8 GB Ubuntu 22.04 VPS. After the fix:
- CPU usage dropped from 85 % to 43 % during peak hours.
- Redis memory consumption stabilized at 1.6 GB.
- Queue latency fell from 12 seconds to 2 seconds.
- WordPress sites on the same VPS saw a 15 % page‑load improvement because PHP‑FPM freed memory for Apache’s
mod_php.
Before vs After Results
| Metric | Before | After |
|---|---|---|
| Queue Failures/hr | 62 | 0 |
| Cron Success Rate | 96 % | 99.9 % |
| Avg. PHP‑FPM RAM | 3.1 GB | 2.1 GB |
| Page‑Load (WordPress) | 1.9 s | 1.6 s |
Security Considerations
- Run Laravel queue workers under a non‑root user (e.g.,
www-data). - Enable Redis AUTH in
redis.confand store the password in.envasREDIS_PASSWORD. - Lock down
/etc/php/8.2/fpm/pool.d/permissions to640(owner root, group www‑data). - Set
disable_functions=exec,passthru,shell_exec,systeminphp.inifor shared hosts.
Bonus Performance Tips
- Enable
opcache.jit_buffer_size=64Mon PHP 8.2 for JIT acceleration. - Use
Redis::pipeline()for bulk writes in Laravel jobs. - Compress MySQL traffic with
net_buffer_length=16384andskip-name-resolve. - Deploy
Laravel Octanewith Swoole on the same VPS for high‑throughput APIs.
FAQ
Q: My queue still dies after the fix. What next?
A: Check /var/log/laravel/queue.log for unhandled exceptions. Most often it’s a memory leak in a third‑party package. Update Composer with composer update --optimize-autoloader.
Q: Can I use the same settings on a 2 GB VPS?
A: Reduce pm.max_children to 12 and set Redis maxmemory 1g. Monitor with htop and adjust.
Q: Do I need both Supervisor and systemd?
A: Supervisor is the de‑facto standard for Laravel queue workers because it provides per‑process autorestart and easy scaling. Systemd can manage the Supervisor service itself.
Final Thoughts
The “queue worker die” nightmare is rarely a Laravel bug; it’s a server‑resource mismatch. By aligning PHP‑FPM pool sizes, allocating proper Redis memory, and letting Supervisor guard your workers, you regain control in minutes—not hours. The same principles apply to WordPress sites on the same VPS, giving you a unified optimization roadmap.
No comments:
Post a Comment