Laravel Queue with Supervisor on Ubuntu (Complete Production Guide)

Laravel queues work well in local development, but configuring the queue processor on your own Ubuntu server can be a hassle. In this blog, we discuss a production-ready Laravel queue setup using Supervisor and highlight common production mistakes.
The basic setup is already covered in the official Supervisor documentation. Here, we go deeper into understanding each step and why it matters.
Supervisor
Supervisor is a process control system for Unix-like operating systems. Its main role is to start, stop, monitor, and automatically restart long-running processes such as queue workers, background jobs, daemons, and custom scripts.
Why is it needed?
During local development, we usually run the following command to process jobs:
php artisan queue:work
This works fine on a local machine, but it is not suitable for production environments. In production, processes must be resilient and always running.
Supervisor solves this problem by managing long-running processes like Laravel queue workers. If the worker crashes or exits unexpectedly, Supervisor automatically restarts it, ensuring continuous job processing. It can also be configured to start automatically when the server boots.
Installing Supervisor
Run the following command to install Supervisor on your Ubuntu server:
sudo apt-get install supervisor
Configuring Supervisor
Supervisor configuration files are typically stored in the /etc/supervisor/conf.d directory. You can create any number of configuration files in this directory that instruct Supervisor on how your processes should be monitored.
For example, let's create a laravel-worker.conf file that starts and monitors a queue:work process:
sudo nano /etc/supervisor/conf.d/laravel-worker.conf
Paste the following configuration into the file:
[program:laravel-worker] process_name=%(program_name)s_%(process_num)02d command=php /var/www/your-app/artisan queue:work sqs --sleep=3 --tries=3 --max-time=3600 autostart=true autorestart=true stopasgroup=true killasgroup=true user=www-data numprocs=8 redirect_stderr=true stdout_logfile=/var/www/your-app/storage/logs/worker.log stopwaitsecs=3600
Understanding the Configuration
Let's break down the critical directives ensuring your workers run smoothly in production:
process_name: Because we are running multiple processes (numprocs=8), this directive ensures each process has a unique name (e.g.,laravel-worker_00,laravel-worker_01).command: This is the actual command Supervisor will run. Make sure to point to the correctartisanpath and specify your connection (likesqsorredis) and any flags.autostart&autorestart: Critical for uptime. These ensure the process starts on boot and restarts automatically if it crashes.user: The system user that will run the process. This should generally match your web server user (oftenwww-dataorubuntu) to avoid permission issues.numprocs: The number of worker processes to run. Increasing this allows you to process jobs in parallel, but be mindful of CPU and memory usage.stopwaitsecs: This should be greater than the time consumed by your longest-running job. It gives the worker time to finish its current job before being forcefully killed during a graceful stop.
Starting Supervisor
Once the configuration file acts created, you need to update the Supervisor configuration and start the processes.
Run the following commands:
sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start laravel-worker:*
reread: Tells Supervisor to check for any new or modified configuration files.update: Applies any changes found during the reread.start: Manually starts the process group (thoughautostart=trueusually handles this).
Managing Processes
Supervisor provides a command-line tool supervisorctl to manage your processes easily.
Check the status of your workers:
sudo supervisorctl status
You should see output indicating that all 8 processes are RUNNING.
To restart all workers:
sudo supervisorctl restart laravel-worker:*
To stop all workers:
sudo supervisorctl stop laravel-worker:*
Deployment Considerations
There is one critical command you must run during every deployment if you change your code.
Since queue workers are long-running processes, they load your application code into memory once when they start. They will not reflect any code changes you push to your repository until they are restarted.
Add this to your deployment script (e.g., usually after composer install and migrations):
php artisan queue:restart
This command gracefully instructs all workers to exit after they finish their current job. Supervisor, noticing they have exited, will simply restart them (thanks to autorestart=true), loading your fresh code.
Frequently Asked Questions
Cron is designed for scheduled tasks (running once every minute/hour/day), not for keeping a process running continuously. Queue workers need to run constantly to process jobs instantly. Supervisor monitors the process and restarts it immediately if it fails, which cron cannot do effectively.
We configured stdout_logfile to point to /var/www/your-app/storage/logs/worker.log. You can tail this file to see the output from your workers:
tail -f /var/www/your-app/storage/logs/worker.log
This is useful for debugging failed jobs or processing errors.
Each worker process consumes memory and CPU. If you set numprocs too high for your server configuration, you might run out of RAM (OOM errors) or cause high CPU context switching, which can actually slow all processes down. Start with a reasonable number (e.g., match your CPU core count) and monitor server resources.