Data & Enterprise
Background Jobs
A job is a named unit of work you queue
rather than call — for slow work a request shouldn't wait on, retried
delivery, or recurring maintenance. Failures are contained, ordering is
deterministic, and schedules read like a sentence.
Declaring & queueing a job
A job … end takes parameters with with. Enqueue a
run with queue Name [with args]. Queued work runs when the
script ends — or, in a service, before the response returns — FIFO:
job SendWelcome
with user_id, name
log info "welcoming" with { "user": user_id }
end
queue SendWelcome with 42, "Zia"
show "main done" # prints first — the job runs as work drains
A job has no caller waiting for a return value and no caller to crash. That's the whole point: it runs on the background timeline, and a failure becomes a log event, not an exception.
Delayed execution
Defer a run with after N seconds | minutes | hours. Delays
ride the same deterministic timeline as timers —
ordering, never a wall-clock sleep, so tests stay instant:
queue SendWelcome with 42, "Zia" after 5 minutes
Retries & the dead-letter story
A failing run is contained. Add
retry N times [waiting M seconds] to re-run it — each failed
attempt that will retry emits a warning, and the final failure
emits an error and counts toward jobs_failed():
job ChargeCard
with order_id
retry 3 times waiting 30 seconds
# ... attempt the charge ...
end
Retries go to the back of the queue, so other work runs between attempts. When retries are exhausted the run is recorded as a dead letter (an error event, category jobs) — the one signal worth alerting on.
Recurring schedules
schedule Name every … registers a recurring run in one of
exactly three English shapes — no cron strings:
schedule Cleanup every 15 minutes
schedule Report every day at "03:00"
schedule Digest every monday at "09:00"
Schedules run on the wall clock. Under zornux serve, the host
pumps jobs and schedules between requests; missed runs (while the host was
busy or down) collapse into one rather than replaying. Scheduled jobs take
no parameters.
Named queues & visibility
Group work with in queue "name", and inspect the queue with
built-ins:
job SendReceipt in queue "emails"
with order_id
retry 3 times
log info "receipt sent"
end
show jobs_pending() # runs waiting anywhere
show queue_pending("emails") # runs waiting in one queue
show jobs_failed() # the dead-letter count
The /health payload carries the
same vitals: "jobs": { pending, failed, schedules }.
Running the workers
| Setting | Effect |
|---|---|
job_workers = 0 | Background pumping off in serve (jobs still drain per request). |
job_workers = 1 | The host pumps jobs and schedules between requests. It's a 0/1 switch — a single background worker on the one host thread, never concurrent with a route. |
Queues and schedules live in memory — they don't survive a restart. Durable stores are a planned addition.
One new keyword: job.