Sunday, May 10, 2026

Laravel Queue Workers Stuck on 100% CPU—Why My VPS Hits 100% Load and How to Fix It in 5 Minutes

Laravel Queue Workers Stuck at 100% CPU—Why My VPS Hits 100% Load and How to Fix It in 5 Minutes

You’ve watched the same “100 % CPU” graph bounce on your monitoring dashboard for the last 30 minutes while the queue never empties. Your Laravel job‑processor feels like a hamster on a wheel, and every deployment you push adds another spike. If you’re a senior PHP developer or a WordPress‑powered SaaS owner, this nightmare is all too familiar. In the next few minutes you’ll learn exactly why the workers choke, how to tame the CPU demon on a typical Ubuntu VPS, and walk away with a bullet‑proof configuration you can paste into supervisor, php‑fpm and nginx in less time than a coffee break.

TL;DR: Mis‑configured queue workers, missing cache, and a hungry PHP‑FPM pool are the usual suspects. Adjust supervisord.conf, enable Redis, tune php-fpm limits, and add a simple php artisan queue:restart. You’ll see CPU drop from 100 % to a comfortable 5‑15 % within minutes.

Why This Matters

When a single VPS runs at full load, every request slows down—WordPress front‑ends become sluggish, API endpoints time out, and your customers start abandoning the checkout flow. In a production SaaS even a 0.5‑second latency increase can shave 10 % off conversion rates. Moreover, cloud providers bill by CPU‑time; an overloaded queue can cost you an extra $50–$200 per month for no reason.

Common Causes of 100 % CPU Queue Workers

  • Too many concurrent workers for the available CPU cores.
  • Laravel Horizon/Dusk using the sync driver accidentally.
  • Missing Redis or database cache causing each job to hit MySQL repeatedly.
  • PHP‑FPM pm.max_children set far too high, leading to fork‑bomb‑like behavior.
  • Infinite loops or unhandled exceptions that restart the job endlessly.
  • Out‑of‑date Composer autoload causing class‑loader thrashing.

Step‑by‑Step Fix Tutorial

1. Verify the Queue Driver

php artisan tinker
>>> config('queue.default')

If it returns sync, switch to redis or database and restart the workers.

2. Install & Configure Redis

# Install Redis on Ubuntu
sudo apt-get update && sudo apt-get install -y redis-server

# Enable and start
sudo systemctl enable redis-server
sudo systemctl start redis-server

# Laravel .env
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
TIP: Keep Redis in protected-mode no only on a private VPS. For public clouds enable a password and firewall.

3. Tune Supervisor

# /etc/supervisor/conf.d/laravel-queue.conf
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
user=www-data
numprocs=4                ; match your CPU cores (2‑4 is safe)
redirect_stderr=true
stdout_logfile=/var/log/laravel/queue.log
stopwaitsecs=3600

4. Optimize PHP‑FPM Pool

# /etc/php/8.2/fpm/pool.d/www.conf
pm = dynamic
pm.max_children = 30      ; 30 * 30 MB ≈ 900 MB RAM
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 5000
WARNING: Setting pm.max_children higher than your RAM can cause swapping and make CPU look even worse.

5. Restart Services

sudo supervisorctl reread && sudo supervisorctl update
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx

Run top or htop now – you should see the worker processes using a fraction of a core.

VPS or Shared Hosting Optimization Tips

  • VPS: Use cgroups to cap CPU per container, or enable nice/cpulimit on the supervisor command.
  • Shared Hosting: Offload queues to a managed Redis service (e.g., Laravel Vapor, UpCloud) and run workers on a low‑cost DigitalOcean droplet.
  • Disable opcache.validate_timestamps=0 in production to reduce file‑stat overhead.
  • Set APP_ENV=production and APP_DEBUG=false – debug mode adds ~5 % CPU.

Real World Production Example

Acme SaaS runs a 2‑core Ubuntu 22.04 VPS with 4 GB RAM, serving a Laravel API and a WordPress blog. Before the fix:

  • Queue workers: 8 processes, each at 100 % CPU.
  • PHP‑FPM: pm.max_children=100 → swapping.
  • Response time: 2.9 s average.

After applying the steps above:

  • Queue workers: 4 processes, 8 % CPU total.
  • PHP‑FPM: pm.max_children=30, no swapping.
  • Response time: 0.9 s average.

Before vs After Results

MetricBeforeAfter
CPU (total)100 %12 %
Queue lag≈ 15 min≈ 30 sec
Memory usage2.3 GB (swap)1.1 GB (no swap)
Avg. API latency2.9 s0.9 s

Security Considerations

  • Never expose Redis without a password on a public IP.
  • Set disable_functions=exec,passthru,shell_exec in php.ini for shared hosts.
  • Use sudo -u www-data when running artisan via supervisor to limit file system access.
  • Keep Composer dependencies up‑to‑date: composer audit weekly.

Bonus Performance Tips

  • Enable opcache.preload with a preload.php that loads common Laravel classes.
  • Set redis.maxmemory 256mb and volatile-lru eviction policy for queue payloads.
  • Turn on query_cache_type=ON in MySQL for frequently read config tables.
  • Use php artisan schedule:work on a separate low‑priority worker.
  • Compress Nginx responses with gzip on; and enable brotli for API traffic.

FAQ

Q: My queue still spikes after the fix. What else can I check?

A: Look for long‑running jobs (e.g., image processing) and offload them to a dedicated worker or a Docker container with its own CPU quota.

Q: Can I run Laravel queues on the same server as WordPress?

Yes, but isolate PHP‑FPM pools – create a separate www.conf for WordPress (lower pm.max_children) and another for Laravel (higher). Keep their listen sockets separate.

Q: Do I really need Supervisor?

Supervisor gives you process monitoring, auto‑restart, and graceful shutdown. Without it you’ll have to script systemd units manually, which is error‑prone.

Q: My VPS provider limits CPU to 1 core. How many workers should I run?

Start with numprocs=1. Then benchmark the job latency. If it’s acceptable, keep it. Adding more will just cause CPU contention.

Final Thoughts

High CPU on Laravel queue workers is rarely a hardware problem; it’s almost always a mis‑configuration that can be solved in minutes. By aligning your queue driver, Redis cache, Supervisor process count, and PHP‑FPM pool, you turn a frantic 100 % monster into a calm, cost‑effective service. Apply the snippets, test in a staging environment, and you’ll see the same performance jump that many SaaS teams credit for a 30 % revenue boost.

Bonus Offer: Looking for cheap, secure VPS hosting to run these optimizations? Hostinger delivers fast SSD servers with 24/7 support – just use the referral code above for an extra discount.

No comments:

Post a Comment