Laravel
Running workers
Run each Laravel background process in its own container, from the same image as your web service. Each worker container needs three settings: the Artisan command, a stop signal, and a health check for that process.
Spin Pro sets up the scheduler, queues, and Horizon on your own server with zero-downtime deployments.
Workers
| Worker | Command | Health check |
|---|---|---|
| Task scheduler | php artisan schedule:work | healthcheck-schedule |
| Queue | php artisan queue:work | healthcheck-queue |
| Horizon | php artisan horizon | healthcheck-horizon |
| Reverb | php artisan reverb:start | healthcheck-reverb |
| Nightwatch | php artisan nightwatch:agent | healthcheck-nightwatch |
Every worker needs three settings
- Command. The images set
WORKDIRto/var/www/html(APP_BASE_DIR), sophp artisanworks as written. The container runs only this process: no web server, no PHP-FPM. stop_signal: SIGTERM. Thefpm,fpm-nginx, andfpm-apacheimages setSTOPSIGNAL SIGQUIT, the graceful stop signal for PHP-FPM and S6 Overlay. Laravel's workers stop gracefully onSIGTERM, and Horizon doesn't handleSIGQUITat all, so setSIGTERMon every worker. Thecliandfrankenphpimages already stop withSIGTERM.- A health check. The image's own health check tests the web server or PHP-FPM, which isn't running in a worker container. Without an override, a worker built from a web variation is marked unhealthy. The
clivariation has no health check. See Health checks for the scripts.
Docker kills a container 10 seconds after the stop signal. If your jobs run longer, raise stop_grace_period on the worker so it can finish the current job.
Laravel automations, including migrations, run in every container that starts with
AUTORUN_ENABLED=true, whatever its command. If your workers share the web service's environment through an env_file or YAML anchor, each one migrates the database at startup. Set AUTORUN_ENABLED=true on one service only.Full Compose example
This example builds on an application image made from serversideup/php:8.5-fpm-nginx. Run queue or horizon, not both: Horizon starts its own queue workers.
compose.yml
services:
app:
image: my-org/my-app:1.0.0
ports:
- "80:8080"
environment:
AUTORUN_ENABLED: "true"
horizon:
image: my-org/my-app:1.0.0
command: ["php", "artisan", "horizon"]
stop_signal: SIGTERM
healthcheck:
test: ["CMD", "healthcheck-horizon"]
start_period: 10s
depends_on:
- redis
scheduler:
image: my-org/my-app:1.0.0
command: ["php", "artisan", "schedule:work"]
stop_signal: SIGTERM
healthcheck:
test: ["CMD", "healthcheck-schedule"]
start_period: 10s
redis:
image: redis:8-alpine
Run a worker inside the web container
To run a worker in the same container as the web server instead, add it as an S6 Overlay service in fpm-nginx or fpm-apache. See Using S6 Overlay. Separate containers are easier to scale and restart on their own.