060 279 5587 info@sitect.co.za 139 Davies Street, Doornfontein, Johannesburg, 2001 Gauteng, SA
Tech Tutorials

A Laravel queue worker that actually stays alive on a R 100/month VPS

Supervisor, sane retry config, OOM guards and a Pushover heartbeat. The exact set-up we put on every R 100/month VPS we deploy a Laravel job runner to.

10 May 2026 · 4 min read · 9 views

Most "how to run Laravel queues in production" tutorials assume you're on a beefy box. Here's the minimal-resources version: a single Hetzner CX21 or similar SA-hosted VPS, ~2GB RAM, running web + queue together.

Supervisor config

We use Supervisor (not systemd directly, because of the per-process restart guarantees). One worker group per critical queue: default, ai, mail. AI jobs sit on their own queue so a slow OpenAI call doesn't block a contact-form email.

[program:sitect-queue-ai]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/sitect/artisan queue:work --queue=ai --tries=3 --backoff=30 --max-time=3600 --memory=192
autostart=true
autorestart=true
user=www-data
numprocs=1
stopwaitsecs=60

--max-time=3600 kicks the worker after an hour so memory leaks (yours or upstream's) don't accumulate. --memory=192 is a hard ceiling.

A heartbeat to Pushover

A scheduled task every 5 minutes that fires a small ping to a heartbeat endpoint. If two consecutive pings don't arrive, Pushover wakes us up. Free tier of healthchecks.io works fine too.

Why this matters for AI workloads

AI jobs are unusual: they're long-running (10–30s), expensive ($0.001–0.05 each) and they fail in interesting ways (rate limits, timeouts, JSON parse errors). Without a healthy worker, leads silently sit in ai_qualifying status forever. Get this right early.