Laravel Queue Workers Stuck on Docker with MySQL on cPanel: 7 Fatal Errors, 0 Jobs, and the 3‑Minute Countdown to Zero‑Down‑Time
If you’ve ever watched a Laravel queue spin forever while your Docker containers scream “Fatal error” and your cPanel dashboard flashes a red 0 jobs counter, you know the feeling: heart‑racing, coffee‑spilling, deadline‑driven panic. In the next few minutes you’ll learn exactly why those workers choke, how to rescue them, and how to turn a dying production line into a zero‑downtime, revenue‑generating machine.
Why This Matters
Queue workers are the bloodstream of any modern SaaS or WordPress‑backed API. When they freeze:
- Critical emails never send.
- Webhooks timeout, breaking partner integrations.
- Background jobs pile up, consuming RAM and CPU until the VPS crashes.
For US‑based SaaS founders, a three‑minute outage can mean lost customers, SLA penalties, and a damaged brand. Fixing the queue is not a nice‑to‑have—it’s a revenue safeguard.
Common Causes
When Laravel, Docker, MySQL and cPanel are mixed together, the most frequent culprits are:
- MySQL connection timeout caused by the default
wait_timeoutof 28800 seconds conflicting with Docker’s 30‑second health‑check. - Supervisor misconfiguration – workers die silently because the
stopwaitsecsis too low. - PHP‑FPM pool limits that cap
pm.max_childrenbelow the number of queue processes. - Missing Redis extension – the Laravel queue fallback to sync, spawning fatal errors.
- cPanel’s cron restrictions that kill Docker exec commands after 180 seconds.
- Composer autoload cache corruption after a recent package update.
- Docker networking – the container cannot resolve the MySQL host name because
docker-compose.ymluseshost.docker.internalon Linux.
Step‑By‑Step Fix Tutorial
1. Verify MySQL Connectivity from Inside the Container
docker exec -it app php artisan tinker
>>> DB::connection()->getPdo();
If you get a SQLSTATE[HY000] [2002] Connection timed out, the DB host is wrong.
2. Update docker-compose.yml to Use the Service Name
services:
app:
build: .
depends_on:
- mysql
environment:
DB_CONNECTION: mysql
DB_HOST: mysql # ← use service name, not localhost
DB_PORT: 3306
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: laravel
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
3. Raise MySQL Timeout Values
Log into the MySQL container and edit my.cnf (or add a custom config):
[mysqld]
wait_timeout=60
interactive_timeout=60
max_allowed_packet=64M
Then restart:
docker-compose restart mysql
4. Fix Supervisor Config
Open /etc/supervisor/conf.d/laravel-queue.conf (inside the app container) and adjust:
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
numprocs=4
redirect_stderr=true
stdout_logfile=/var/log/laravel-queue.log
stopwaitsecs=360 ; ← increase from default 10
startsecs=5
supervisorctl reread && supervisorctl update && supervisorctl restart all inside the container.
5. Tune PHP‑FPM Pool
; /etc/php/8.1/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 5000
6. Install & Enable Redis Extension
docker exec -it app bash
pecl install redis
echo "extension=redis.so" >> /usr/local/etc/php/conf.d/redis.ini
php -m | grep redis # should list redis
7. Clear Composer Autoload & Optimize
docker exec -it app composer dump-autoload -o
php artisan config:clear
php artisan cache:clear
VPS or Shared Hosting Optimization Tips
- Upgrade to PHP‑FPM 8.x – it reduces memory per worker by ~30%.
- Enable OPcache in
php.inifor faster script compilation. - Use Cloudflare DNS + Argo to cut latency between the end‑user and your VPS.
- Allocate at least 2 GB RAM for a Laravel queue on a 4‑core VPS.
- Set MySQL
innodb_buffer_pool_sizeto 70% of RAM on a dedicated DB server. - On shared cPanel, switch to EasyApache 4 and enable “mod_proxy_fcgi” for PHP‑FPM.
Real World Production Example
Acme SaaS runs a Laravel API on a 2‑CPU Ubuntu 22.04 VPS behind Nginx. The queue handles 1,200 email jobs per minute. After applying the steps above, they saw:
- Queue latency drop from 45 seconds to 2 seconds.
- CPU usage stable at 35 % instead of spiking to 95 %.
- No more “0 jobs” alerts in New Relic.
Before vs After Results
| Metric | Before | After |
|---|---|---|
| Jobs Processed/min | 0‑30 | 1,150‑1,300 |
| Avg. Job Latency | 45 s | 2 s |
| Memory Usage | 1.8 GB | 1.1 GB |
Security Considerations
When you open ports for Docker and MySQL, lock them down:
# ufw allow from 10.0.0.0/8 to any port 3306 proto tcp
# ufw limit ssh
# docker network create --internal backend_net
Never expose DB_HOST credentials in public repos. Use .env.production and docker secret for MySQL passwords.
APP_DEBUG in production is critical. Leaving it true can leak stack traces that reveal server paths and DB queries.
Bonus Performance Tips
- Switch Laravel queue driver to
redisinstead ofdatabasefor faster job dequeuing. - Enable
queue:restartvia a cron job after every deployment. - Use
php artisan horizonif you have Redis; it gives real‑time metrics and auto‑scales workers. - Compress static assets with
gziporbrotliin Nginx. - Set
realpath_cache_size=4096kinphp.inifor large Laravel codebases.
FAQ
Q: My queue still shows “0 jobs” after the fix.
A: Verify that theQUEUE_CONNECTIONin.envmatches the driver you configured (redis vs database) and clear the cache.
Q: Can I run this on a shared cPanel hosting without Docker?
A: Yes. Replace Docker exec commands with SSH commands, usephp artisan queue:workunder a cron that callsnohup, and switch MySQL host to the cPanel provided hostname.
Final Thoughts
Docker, cPanel, and Laravel can coexist peacefully, but only if you respect the low‑level timeouts and process limits of each layer. The seven fatal errors you saw are just symptoms of a mis‑aligned stack. By aligning MySQL timeouts, fixing Supervisor, and giving PHP‑FPM the breathing room it needs, you gain a queue that never stalls, a VPS that stays cool, and a SaaS that continues to ship revenue.
Remember: Automation + Monitoring = Zero‑Downtime. Deploy Horizon, add New Relic alerts for queue:work failures, and schedule a nightly queue:restart. Your future self will thank you.
No comments:
Post a Comment