Saturday, May 9, 2026

Fix Laravel “Queue Workers Crash on Ubuntu 22.04 – MySQL Deadlocks and PHP‑FPM Memory Leak” causing 500 errors on shared cPanel hosting

Fix Laravel “Queue Workers Crash on Ubuntu 22.04 – MySQL Deadlocks and PHP‑FPM Memory Leak” Causing 500 Errors on Shared cPanel Hosting

If you’ve ever watched your Laravel queues die with a mysterious “500 Internal Server Error” on a cheap shared cPanel VPS, you know the frustration feels like a hard‑reset on a production site. One minute the API is humming, the next the workers explode, MySQL tables lock, and PHP‑FPM hoards memory until the whole app goes dark. This article shows you, step‑by‑step, how to diagnose the root cause, apply a bullet‑proof fix, and tune both the Laravel queue and the underlying Ubuntu 22.04 stack for long‑term stability.

Why This Matters – A crashing queue not only returns 500 errors to users, it can corrupt data, break email pipelines, and cripple any background jobs that power your SaaS. Fixing it today saves countless hours of emergency support tickets and protects revenue streams.

Why This Matters

Laravel queue workers are the backbone of real‑time notifications, order processing, and API throttling. When a worker dies, every pending job sits idle, and customers see time‑outs or lost confirmations. On shared hosting the problem is amplified because you share CPU, RAM, and MySQL with dozens of other accounts, making resource exhaustion harder to spot.

Common Causes on Ubuntu 22.04 + cPanel

  • PHP‑FPM pm.max_children set too high, causing out‑of‑memory (OOM) kills.
  • MySQL innodb lock waits leading to deadlocks when multiple workers update the same rows.
  • Supervisor not restarting crashed workers fast enough.
  • Redis connection time‑outs due to low tcp‑keepalive settings.
  • Composer autoload cache corruption after a failed deployment.

Step‑By‑Step Fix Tutorial

1. Verify the Exact Error

Check /var/log/php-fpm/error.log and /home/username/logs/laravel.log. You’ll typically see entries like:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted...
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock;

2. Tame PHP‑FPM Memory Usage

Open the PHP‑FPM pool config for your domain (usually /opt/cpanel/ea-php*/root/etc/php-fpm.d/www.conf) and adjust:

# Recommended for 2 GB shared plan
pm = dynamic
pm.max_children = 12
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
php_admin_value[memory_limit] = 128M

After saving, restart PHP‑FPM:

service php-fpm restart

3. Resolve MySQL Deadlocks

Fine‑tune InnoDB settings and add explicit row‑level locking in your jobs.

# /etc/my.cnf.d/innodb.cnf
[mysqld]
innodb_lock_wait_timeout = 50
innodb_rollback_on_timeout = ON
innodb_flush_method = O_DIRECT

Run systemctl restart mysqld. Then modify the job:

public function handle()
{
    DB::transaction(function () {
        $order = Order::where('id', $this->orderId)
                      ->lockForUpdate()
                      ->first();

        // business logic…
        $order->status = 'processed';
        $order->save();
    });
}

4. Configure Supervisor Properly

Supervisor keeps your queue workers alive. Create or edit /etc/supervisor/conf.d/laravel-queue.conf:

[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /home/username/laravel/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
user=username
numprocs=4
redirect_stderr=true
stdout_logfile=/home/username/logs/queue.log
stopwaitsecs=3600

Then reload:

supervisorctl reread && supervisorctl update && supervisorctl start laravel-queue:* 

5. Harden Redis Connectivity

Add keep‑alive and increase timeout in /etc/redis/redis.conf:

tcp-keepalive 60
timeout 0

Restart Redis:

systemctl restart redis

6. Refresh Composer Autoload Cache

After any package change, run:

composer dump-autoload -o
php artisan clear-compiled
php artisan optimize

7. Test the Whole Stack

Queue a test job from Tinker:

php artisan tinker
>>> dispatch(new \App\Jobs\SendInvoice($orderId));

Monitor logs for 2‑5 minutes. No more “500” entries → success.

TIP: Keep pm.max_children roughly equal to (total RAM – 200 MB) / memory_limit. Over‑provisioning is the fastest way to trigger OOM kills on shared plans.

VPS or Shared Hosting Optimization Tips

  • Use Swap only as a last resort. On a 1 GB VPS, allocate 512 MB swap to avoid sudden OOM kills.
  • Enable opcache.enable_cli=1 for faster Artisan commands.
  • Prefer Redis over database driver for cache and queue on shared servers.
  • Set APP_DEBUG=false in production to prevent memory‑heavy stack traces.
  • Deploy via Git hooks that run composer install --no-dev --optimize-autoloader automatically.

Real World Production Example

Acme SaaS runs a multi‑tenant Laravel app on a 2 GB Ubuntu 22.04 VPS with cPanel. Before the fix they saw 30‑40% of HTTP 500 errors during peak sign‑up hours. After applying the memory‑tuned PHP‑FPM, InnoDB lock adjustments, and a 4‑process Supervisor config, error rates dropped to under 0.5%. The queue latency went from an average of 12 seconds to 2.3 seconds.

Before vs After Results

Metric Before After
PHP‑FPM Memory (MB) 256 per child 128 per child
Queue Workers 2 processes (frequent crashes) 4 processes (stable)
MySQL Deadlocks 12 per hour 0‑1 per day
Avg Job Latency 12 s 2.3 s

Security Considerations

While tuning performance, never compromise security:

  • Keep APP_KEY secret; regenerate after a fresh composer install.
  • Enable firewall-cmd or ufw to limit MySQL to localhost.
  • Use redis-cli ACL SETUSER to require password authentication.
  • Set disable_functions in php.ini to block exec, shell_exec unless needed.
WARNING: Disabling opcache.validate_timestamps on shared hosting can hide code updates. Only enable if you fully control the deployment pipeline.

Bonus Performance Tips

  • Switch Laravel Horizon for Redis‑backed job monitoring; it gives real‑time metrics and auto‑scales workers.
  • Use php artisan schedule:work instead of cron for tighter timing on cPanel.
  • Compress outgoing API JSON with ob_gzhandler in .htaccess or Nginx gzip block.
  • Leverage Cloudflare page rules to cache static assets and reduce server load.
  • Store large blobs (images, PDFs) on S3 and serve via a CDN – removes MySQL BLOB pressure.

FAQ

Q: My shared cPanel account doesn’t allow editing php-fpm pools. What can I do?
A: Use the “MultiPHP Manager” in WHM to set a custom php.ini with a lower memory_limit. Then limit queue workers to 2 processes via php artisan queue:work --daemon --sleep=5.
Q: Do I really need Supervisor on shared hosting?
A: On cPanel you can use “Cron Job” to launch queue:work --daemon every minute, but Supervisor gives instant restarts and is worth a small VPS upgrade.

Final Thoughts

Laravel queue crashes on Ubuntu 22.04 are rarely a one‑off bug; they are a symptom of an unbalanced stack. By aligning PHP‑FPM memory, MySQL lock settings, Redis keep‑alive, and a robust Supervisor config, you turn a flaky 500‑error nightmare into a rock‑solid background processor. The same principles apply whether you run on a $5 shared cPanel plan or a $30 VPS – scaling is simply a matter of proportion.

SUCCESS: Implement the steps above, and your queue workers will stay alive, your MySQL will stay deadlock‑free, and your users will thank you with higher conversion rates.

Looking for Cheap, Secure Hosting?

If you’re ready to migrate to a provider that gives you full root access, built‑in Redis, and one‑click Laravel deployment, check out Hostinger’s ultra‑affordable VPS plans. They include managed backups, free SSL, and a 30‑day money‑back guarantee – perfect for the budgets of indie developers and small agencies.

No comments:

Post a Comment