Concepts

Jobs

A job is a command to execute. It is created by add and lives in the jobs table as a row with an argv vector, scheduling metadata, retry budgets, and state. Each job has a unique integer ID assigned at creation.

Attempts

Each time a worker executes a job, it creates an attempt row. The attempt records the worker ID, PID, start and finish times, exit code, and paths to captured stdout/stderr files. A job may have multiple attempts if it fails and is retried, or if the worker crashes and the job is re-queued.

Job States

Jobs move through these states:

State Meaning
queued Waiting to be claimed by a worker.
running Currently being executed by a worker.
done Completed successfully (exit code 0).
failed Reserved and never emitted. A failing job with retry budget left returns to queued; it becomes dead once the budget is exhausted.
dead Exhausted all retries; will not be retried automatically.
canceled Explicitly canceled by the user.

State transitions are always mediated by the database under BEGIN IMMEDIATE transactions, never by in-memory logic alone.

Scheduled (derived, not a state)

A queued job with next_run_at in the future is reported as “scheduled” in status counts. This is a query-time derivation, not a stored state. A job delayed by --after 60 and a job delayed by retry backoff both appear as scheduled; only the first reflects user intent.

Attempt States

State Meaning
running Currently executing.
succeeded Completed with exit code 0.
failed Completed with non-zero exit code.
timed_out Exceeded the per-job timeout.
abandoned Abandoned due to worker crash.
canceled Canceled.

Event Ledger

Every state transition writes to the job_events table: an append-only ledger of (job_id, event_type, timestamp, worker_id, detail) rows. The ledger is the daemonless event stream; see Events for how to consume it.

Event types: added, claimed, succeeded, failed, timed_out, reaped, dead, retried, canceled.

Queues (Lanes)

Jobs are assigned to a named queue (default: default). Workers can target a specific queue with work --queue <name>. The --slots N flag on work sets a per-lane ceiling: the worker will not claim a new job in that queue if N jobs are already running there. This is the fleet-wide concurrency control mechanism.

Priorities

Jobs have an integer priority (default: 0, range: -2147483648 to 2147483647). Higher values are claimed first. Within the same priority, the job with the earliest eligible next_run_at is claimed first. Ties on both are broken by job ID (insertion order).

Claim Order

Workers claim the next eligible job using:

priority DESC, next_run_at ASC, id ASC

This order is enforced by a covering index. Two workers racing to claim the same job are serialized by BEGIN IMMEDIATE; exactly one succeeds.

Failure Reasons

When an attempt ends in failure, the reason is recorded:

Reason Recorded by
process_exit Worker execution (non-zero exit code).
timeout Worker execution (exceeded timeout).
spawn_failed Worker execution (could not start the command).
worker_crash Reaping (worker died without recording a result).
canceled Cancel or force-retry.
unknown Historical backfill for pre-v6 failures.

See Guarantees for how these interact with retry budgets.