Skip to main content

PHP Queues and Supervisor: Worker Processes for Laravel

PHP · 29.09.2026

A queue lets you move slow work — sending emails, generating reports, processing uploaded files — out of an HTTP request into a background process. Both Laravel and Symfony can put jobs into a queue, but the job handler itself is a separate long-running PHP process that needs to be watched. That is exactly what Supervisor is for.

Why a separate worker process is needed

A command like php artisan queue:work in Laravel or messenger:consume in Symfony starts once and keeps running until it is stopped or crashes from an unhandled exception. Without a supervisor, such a process eventually terminates, and jobs pile up in the queue with no handler at all. Setting up Symfony itself on a server is covered in the article on Symfony on a VPS.

Supervisor is a daemon that starts the specified processes, restarts them on a crash, and lets you keep several identical workers running at once for parallel queue processing.

Installation and a base config

sudo apt install supervisor
sudo mkdir -p /etc/supervisor/conf.d
sudo nano /etc/supervisor/conf.d/laravel-worker.conf

An example config for a Laravel queue with several workers:

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/app/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
directory=/var/www/app
autostart=true
autorestart=true
user=www-data
numprocs=4
redirect_stderr=true
stdout_logfile=/var/www/app/storage/logs/worker.log
stopwaitsecs=3600

Key config settings

SettingValueWhy it matters
numprocs4number of parallel workers per queue
autorestarttruerestart when the process crashes
stopwaitsecs3600time to finish the current job before kill
max-time / --time-limit3600scheduled worker restart once an hour

The scheduled restart matters: a PHP process that runs for hours gradually accumulates memory from leaks in third-party libraries. Once an hour, Supervisor simply brings up a fresh copy of the process instead of the old one.

Management commands and applying the config

  • supervisorctl reread — Supervisor sees a new or changed config file in conf.d.
  • supervisorctl update — applies the changes: starts new programs, stops removed ones.
  • supervisorctl restart laravel-worker:* — restarts every worker in the group after deploying new code.
  • supervisorctl status — shows the state of each worker and the time of its last start.

Common reasons jobs get stuck or lost

After deploying a new release, old workers keep running the old code still in memory until they are restarted by hand with supervisorctl restart — that step is worth adding to the deploy script as mandatory. Another common cause is a worker holding a database connection that MySQL drops after an idle timeout, and the next job then fails with "MySQL server has gone away". For CLI worker runs it helps to understand the difference from request handling through FPM — covered in the article on PHP CLI and FPM. The easiest way to diagnose crashes is through the worker's own log and the general PHP error log — the parsing process is described in the article on parsing PHP logs.

Checklist for queue setup in production

  1. Set --tries and --max-time in the worker command so a stuck job does not block the queue forever.
  2. Add supervisorctl restart to the deploy script right after updating the code on the server.
  3. Set up a separate log for workers and monitor the queue length so you notice a growing backlog before your users do.
← Back to Knowledge Base Ask Support