Laravel queue workers on shared hosting: always on via cron
Laravel queue workers on shared hosting: always running via cron
Do you use Laravel queues for email, imports or other background tasks? Then you need a queue worker that processes the jobs. On a VPS you would usually use Supervisor for that. Supervisor is not available on our shared hosting, but you do not need it either. With a cron job and flock you keep a worker running continuously, and it starts up again on its own after a restart or outage.
How it works
Cron tries to start the worker every minute. flock makes sure that never more than one instance runs at the same time:
- If the worker is already running, the new attempt stops immediately.
- If the worker has stopped, for example after a server restart, a crash or a deploy, cron starts it again within a minute.
- With
--max-timethe worker stops cleanly after a fixed time. That keeps memory usage low and means it always runs your latest code.
This gives you the same result as Supervisor, without extra software.
What do you need?
- A hosting plan with SSH and cron jobs, such as Webhosting Starter or higher.
- A Laravel project that is already running. See Installing Laravel on shared hosting.
Step 1: choose the database as the queue
Set this in your .env:
QUEUE_CONNECTION=database
Since Laravel 11, the jobs table is included by default in a new project. Do you have an older project without that table? Create it via SSH:
php artisan make:queue-table
php artisan migrate
Tip: on our platform, Redis is meant as a cache. After a restart, recent data may be gone. So choose the database for jobs that must not be lost, such as email.
Step 2: create a folder for the lock files
Log in via SSH and run:
mkdir -p ~/locks
Step 3: create the cron job
In DirectAdmin, go to Cronjobs (see Setting up cron jobs in DirectAdmin). Enter a * in every field for minute, hour, day, month and weekday, so that the cron job runs every minute. Use this as the command:
/usr/bin/flock -n /home/GEBRUIKER/locks/worker1.lock /usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan queue:work --max-time=3600 --sleep=3 --tries=3 > /dev/null 2>&1
Replace GEBRUIKER with your DirectAdmin username and PAD-NAAR-PROJECT with the folder of your Laravel project, for example domains/jouwdomein.nl/laravel.
What each part does:
flock -n ...worker1.lock: only starts the worker if none is running yet./usr/local/bin/php: uses the PHP version you chose in DirectAdmin under Select PHP version.--max-time=3600: the worker stops cleanly after an hour and cron immediately starts a new one.--sleep=3: when the queue is empty, the worker checks every 3 seconds for new jobs.--tries=3: a job that fails is tried at most 3 times and then ends up in thefailed_jobstable.
Step 4: the scheduler (if you use it)
If you use the Laravel scheduler, add a second cron job that runs every minute:
/usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan schedule:run > /dev/null 2>&1
Do not also start the queue worker from the scheduler. The cron job from step 3 already takes care of that.
More than one worker
Need more processing capacity? Then add a second cron job with its own lock file:
/usr/bin/flock -n /home/GEBRUIKER/locks/worker2.lock /usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan queue:work --max-time=3600 --sleep=3 --tries=3 > /dev/null 2>&1
Each worker needs its own lock file. With the same lock, only one runs at a time. Want one worker per queue, for example for email? Then add --queue=mail.
After a deploy
Workers keep your code in memory. After uploading new code, run:
php artisan queue:restart
The workers finish their current job and stop. Within a minute, cron starts them again with the new code.
Checking that the worker is running
ps -u $USER -o pid,etime,cmd | grep "queue:work" | grep -v grep
If you see a line with artisan queue:work, the worker is running. You can view failed jobs with:
php artisan queue:failed
Good to know
- A worker usually uses about 50 to 100 MB of memory. That counts toward the limits of your hosting plan.
- Do not start a worker with
nohupor&. A worker like that does not come back after a restart, and withoutflockyou can easily start several by accident. - Only a few jobs? Then you can do without a permanent worker: let cron run
queue:work --stop-when-emptyevery minute, also withflock. The worker then processes whatever is waiting and stops. - If you run a test environment and a production environment in separate hosting plans, each plan has its own cron jobs, workers and database.
Need help?
Stuck? Send us a message through the ticket system and we will take a look with you.
Looking for hosting for your Laravel app? View Laravel hosting.
0 of 0 found this helpful