Zornux docs
Get started Spec

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:

zornux
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
Queued, never called

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:

zornux
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():

zornux
job ChargeCard
    with order_id
    retry 3 times waiting 30 seconds
    # ... attempt the charge ...
end
A failed job never crashes the program

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:

zornux
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:

zornux
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

SettingEffect
job_workers = 0Background pumping off in serve (jobs still drain per request).
job_workers = 1The 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.
In-memory queues

Queues and schedules live in memory — they don't survive a restart. Durable stores are a planned addition.

One new keyword: job.