Workers & jobs
Not everything answers HTTP. Workers keep running in the background, jobs run to completion on a schedule or on demand, and one-off commands run once in the live release.
Workers
A worker is a service without a port: queue consumers, bots, stream processors. It deploys like any other service — same builds, releases, variables, logs, metrics, rollback, and autoscaling — but has no address and can’t have domains.
apprail services create shop worker --worker
apprail build shop/worker --git https://github.com/acme/shop --context worker- Healthy means “stayed running”. With no port to check, a new instance counts as ready once its process has stayed up for 15 seconds. A process that exits straight away fails the deployment instead of passing.
- Workers don’t receive
PORT; everything else is the same. - The kind is fixed when a service is created. To turn a worker into a web service, create a new service.
- Shut down cleanly on
SIGTERM: stop taking new work and finish what you have within 30 seconds.
Jobs
A job is a named command attached to a service and environment. Each run starts a fresh container from the service’s live release — same image, variables, CPU, and memory — runs the command through sh -c, and records its exit code, duration, and output.
apprail jobs create shop/web nightly-report --schedule "0 3 * * *" --timezone Europe/Stockholm -- node scripts/report.js
apprail jobs run shop/web nightly-report
apprail jobs runs shop/web nightly-report
apprail jobs logs RUN_ID| Option | What it does |
|---|---|
--schedule | Five-field cron, or @hourly, @daily, @weekly, @monthly, @yearly. At most every 5 minutes. Leave it out for a job you only run by hand |
--timezone | An IANA zone; default UTC. 0 3 * * * in Europe/Stockholm runs at 03:00 local time all year, across daylight-saving changes |
--concurrency | forbid (default) skips a run while the previous one is still going; replace stops the old run; allow runs both |
--retries | Extra attempts after a failure, 0–5 |
--timeout | Seconds before a run is stopped; default one hour |
- Exactly once per time slot, however many Apprail workers are running.
- After an outage, only the most recent missed run happens — never a burst of every run that was missed.
- Runs receive
APPRAIL_JOB_NAMEandAPPRAIL_JOB_RUN_ID, and noPORT. - The last 100 runs per job are kept, each with up to 256 KB of output. Cancel an active run with
apprail jobs cancel RUN_ID. - A job needs something live to run against; deploy the service first. A job can’t be deleted while it is running.
- The console’s Jobs page lists jobs, runs them, pauses and resumes schedules, and shows each run’s output.
A job that starts failing sends one alert to your alert channels — not one per run — and another only after it has succeeded again.
One-off commands
Seed a database, fix some data, run a script once. apprail run starts the command in the live release with the environment’s variables and streams its output back until it exits. It exits with the command’s own exit code, so it works in scripts and CI. Ctrl-C cancels it. The console’s Run a command does the same.
apprail run shop/web -- npx prisma db seed
apprail run shop/web --env staging -- python manage.py createsuperuser --noinput- Runs are limited to one hour and are recorded in the activity history with their command.
- In a protected environment only owners and admins, signed in to the console, can run commands — they run with that environment’s secrets.
- Commands aren’t interactive: there’s no shell or prompt attached to your terminal. Pass everything as arguments or variables.
Which one to use
| You want to… | Use |
|---|---|
| Migrate the database before every release | a pre-deploy command |
| Do something once, now | apprail run |
| Do something on a schedule | a job with --schedule |
| Keep something running | a worker |