⏱️
Hosting

Running Laravel Queues and the Scheduler on a Server: cron, Supervisor, Shared Hosting

10.11.2026
← All articles

In Laravel, heavy tasks such as sending emails and SMS, building reports or processing images usually go onto a queue, while recurring work is handed to the scheduler. Locally a developer runs php artisan queue:work in a terminal and everything works. After deployment, jobs pile up and never run, because nobody started the process that reads them.

How queues and the scheduler actually work

The application writes a job to a queue, for example the jobs table or Redis. A separate long-running queue:work process picks jobs up and executes them; without it jobs are never lost but never processed either. The scheduler is different: Laravel does not watch the clock itself, so something must call php artisan schedule:run every minute, and that command runs whatever is due.

Take a private clinic in Tashkent whose site misol.uz books appointments. A confirmation SMS is queued at booking time, and every morning at 9:00 reminders go out for the next day. The first needs a permanent worker, the second a scheduler woken every minute. Miss either one and patients get nothing.

Choosing a queue driver

For typical projects the database driver is simplest: set QUEUE_CONNECTION=database in .env. Laravel 11 ships the jobs and failed_jobs migrations by default; older versions create them with php artisan queue:table and php artisan queue:failed-table. Redis is faster under heavy load but has to be installed on a VPS.

One cron line for the scheduler

In Laravel 11, scheduled tasks live in routes/console.php (older versions use app/Console/Kernel.php):

use Illuminate\Support\Facades\Schedule;

Schedule::command('reminders:send')
    ->dailyAt('09:00')
    ->timezone('Asia/Tashkent');

Mind the time zone: a server on UTC would send reminders five hours late. The server needs just one cron entry:

* * * * * cd /var/www/misol && php artisan schedule:run >> /dev/null 2>&1

On shared hosting you add it in the cron section of ISPmanager. Several PHP versions may be installed, so use the full binary path, for example /opt/php82/bin/php; sayt.uz support can confirm the exact path.

A permanent worker with Supervisor on a VPS

A worker can die from memory leaks, reboots or unexpected errors. Supervisor restarts it automatically. Install it with sudo apt install supervisor and create /etc/supervisor/conf.d/misol-worker.conf:

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

numprocs=2 runs two workers, and --max-time=3600 makes each exit after an hour so Supervisor starts a fresh one, keeping memory in check. stopwaitsecs must exceed your longest job. Load it with:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start "misol-worker:*"
sudo supervisorctl status

Shared hosting without Supervisor

When long-running background processes are not allowed, let the scheduler drive the queue: every minute a worker starts, drains the queue and exits.

Schedule::command('queue:work --stop-when-empty --max-time=50')
    ->everyMinute()
    ->withoutOverlapping();

withoutOverlapping prevents stacked processes. Jobs may wait up to a minute, which is fine for confirmations and SMS. For multi-minute jobs such as video conversion or large exports, a VPS is the better choice.

Deploys, failures and monitoring

Workers load your code into memory once, so after every deploy run php artisan queue:restart; workers finish the current job, exit gracefully and come back with the new code. Jobs that fail after all attempts land in failed_jobs; inspect them with php artisan queue:failed and resend with php artisan queue:retry all once the cause is fixed. Check storage/logs regularly too, since an unreachable SMS gateway or a changed mail password usually shows up there first.

Related articles

🚦 MySQL "Too many connections" Error: Causes and Fixes 📁 Connecting to your hosting over SFTP with FileZilla and WinSCP 🗄️ How to Create a Database and User in ISPmanager 🔤 utf8mb4: keeping emoji and Uzbek letters intact in MySQL
🌐 Language
🇺🇿 O'zbek 🇺🇿 Ўзбек 🇷🇺 Русский 🇬🇧 English ✓