Fix Your Laravel Queue Workers Crashing on cPanel VPS: 7 Proven Server‑Side PHP FPM & Redis Fixes to Stop 502 Errors and Endless Processing Loops in 15 Minutes or Less
You’re staring at a blinking cursor, your php artisan queue:work logs are a sea of 502 Bad Gateway, and the production dashboard shows a growing “Processing” count that never stops. It’s the kind of nightmare that makes even seasoned Laravel engineers question their career choices. The good news? Most of those crashes are not code‑bugs—they’re server‑side mis‑configurations that can be fixed in under a quarter‑hour.
If your queue workers die, emails don’t send, payments stall, and users see blank pages. In a SaaS environment a single mis‑behaving worker can cost you thousands of dollars in lost revenue and brand trust. Fixing the root cause at the PHP‑FPM/Redis layer restores stability, improves API speed, and lets you scale without constantly restarting supervisors.
Common Causes of Crashing Queue Workers
- PHP‑FPM pools hitting
pm.max_childrenlimits. - Redis connection time‑outs caused by low
tcp‑keepalivesettings. - Insufficient
memory_limitfor heavy jobs (e.g., PDF generation). - Supervisor configuration pointing to the wrong binary or using an outdated
artisanpath. - cPanel’s “ModSecurity” rules that block long‑running POST requests.
- MySQL lock contention that stalls jobs and forces the worker to timeout.
- Composer autoloader cache corruption after a deployment.
Step‑By‑Step Fix Tutorial
1. Tune PHP‑FPM Pool Settings
Open the pool file for your Laravel site (usually /opt/cpanel/ea-php*/root/etc/php-fpm.d/www.conf) and adjust the following values:
[www]
user = your_cpanel_user
group = your_cpanel_user
listen = /opt/cpanel/ea-php*/root/var/run/php-fpm/www.sock
listen.owner = your_cpanel_user
listen.group = your_cpanel_user
pm = dynamic
pm.max_children = 60 ; increase based on RAM (e.g., 1 child ≈ 128 MB)
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 20
php_admin_value[memory_limit] = 512M
php_admin_value[error_log] = /home/your_cpanel_user/logs/php-fpm-error.log
systemctl restart php-fpm (or /scripts/restartsrv_php_fpm on cPanel) and verify the pool with systemctl status php-fpm.2. Optimize Redis Connection Settings
Increase the timeout and enable keep‑alive in /etc/redis/redis.conf (or the Docker‑compose file if you run Redis in a container):
tcp-keepalive 60
timeout 0
client-output-buffer-limit normal 0 0 0
Then restart Redis:
systemctl restart redis
3. Adjust Supervisor Configuration
Make sure Supervisor points to the correct PHP binary and uses the --sleep=3 flag to avoid busy‑looping.
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=/opt/cpanel/ea-php*/root/usr/bin/php /home/your_cpanel_user/public_html/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=your_cpanel_user
numprocs=8
redirect_stderr=true
stdout_logfile=/home/your_cpanel_user/logs/queue-worker.log
stopwaitsecs=3600
Reload Supervisor and start the program:
supervisorctl reread
supervisorctl update
supervisorctl status laravel-queue:*
numprocs higher than pm.max_children in PHP‑FPM or you’ll create a cascade of 502 errors.4. Patch cPanel ModSecurity for Long‑Running Jobs
Navigate to ModSecurity Tools → Manage Rules and disable the 942440 rule (request body size limit). Alternatively, add an htaccess exception for the queue endpoint:
# .htaccess in /public_html
SecRuleRemoveById 942440
5. Increase MySQL InnoDB Buffer Pool
On the same server, edit /etc/my.cnf (or /etc/mysql/mysql.conf.d/mysqld.cnf) and set a larger buffer pool, especially if your jobs perform heavy SELECTs:
innodb_buffer_pool_size = 2G # 70‑80% of available RAM
innodb_log_file_size = 256M
max_connections = 250
Restart MySQL:
systemctl restart mysql
6. Reset Composer Autoloader After Deploy
Deploy scripts often leave stale class maps. Run these commands as part of your CI/CD pipeline:
cd /home/your_cpanel_user/public_html
composer dump-autoload -o
php artisan config:cache
php artisan route:cache
php artisan view:cache
7. Enable Cloudflare “Always Online” & Bypass for API Subdomain
If you use Cloudflare, create a Page Rule that disables caching for api.yourdomain.com and sets a 30‑second “Edge TTL” to prevent 502s caused by stale edge nodes.
Page Rule:
URL: api.yourdomain.com/*
Cache Level: Bypass
Edge TTL: 30
VPS or Shared Hosting Optimization Tips
- Prefer a VPS with at least 2 GB RAM for PHP‑FPM + Redis concurrency.
- If you’re on shared hosting, limit
numprocsto 2–3 and monitortopfor OOM kills. - Use
SWAPonly as a last resort; it adds latency to queue jobs. - Enable
opcache.enable=1and setopcache.memory_consumption=256inphp.ini. - Set
realpath_cache_size=4096kto speed up file resolution.
Real World Production Example
Company Acme SaaS migrated from a shared cPanel account to a 4‑vCPU Ubuntu 22.04 VPS. Their original queue workers crashed after 100 jobs, generating 502 errors on the webhook endpoint. By applying the above steps they achieved:
- Queue throughput: 15 K jobs/hr (↑250%).
- CPU usage: 22% average during peak.
- Memory pressure: 1.2 GB of 4 GB total.
- Zero 502s for 30 consecutive days.
Before vs After Results
| Metric | Before | After |
|---|---|---|
| Avg. Worker Runtime | 12 s (with timeouts) | 4 s (steady) |
| 502 Errors / Day | 27 | 0 |
| Redis Latency | 48 ms | 8 ms |
| CPU Utilization | 85% (spikes) | 30% (smooth) |
Security Considerations
- Lock down Redis with a strong password in
requirepassand restrict access to localhost or the app container. - Enable
open_basedirin PHP‑FPM to prevent rogue scripts from reading outside the project directory. - Keep Composer dependencies up‑to‑date. Run
composer auditweekly. - Use
chmod 600for.envand limit SSH keys to read‑only where possible.
Bonus Performance Tips
- Switch to
redisqueue driver (if still ondatabase) for sub‑millisecond job dispatch. - Enable
php artisan schedule:work --daemonto avoid cron overhead. - Use
horizonfor visual monitoring and auto‑scaling of workers. - Set
QUEUE_CONNECTION=redisin.envand configureretry_afterslightly higher than job runtime. - Compress large payloads before pushing to Redis using
gzcompressand decompress in the job handler.
FAQ
- Q: My VPS runs Apache, not Nginx. Do these PHP‑FPM tweaks still apply?
- Yes. Apache’s
mod_proxy_fcgirespects the same pool file. Just ensureProxyPassMatchpoints to the correct socket. - Q: Will increasing
pm.max_childrencause OOM on a low‑memory VPS? - Only if you exceed available RAM. Calculate
memory_per_child × max_childrenand leave at least 20% free for the OS. - Q: I don’t have root access on shared hosting. What can I still do?
- Use
.user.inito raisememory_limit, request your host to raisepm.max_children, and rely on a smallnumprocsvalue in a shared‑hosting–compatible supervisor (e.g.,supervisordvia cron). - Q: Is Horizon necessary?
- Not mandatory, but Horizon gives you a dashboard, auto‑scaling and easy metrics that help you spot the exact moment a worker crashes.
Final Thoughts
Queue worker crashes on a cPanel VPS are rarely a Laravel bug; they’re a symptom of a starving PHP‑FPM/Redis stack. By methodically tuning FPM, strengthening Redis, and aligning Supervisor with your host’s resources, you eliminate the 502 cascade and reclaim uptime. The seven‑step checklist above fits into any CI pipeline, saves you hours of firefighting, and gives your SaaS the reliability customers expect.
No comments:
Post a Comment