GizStack
View .mdOpen in ChatGPTOpen in Claude

gizweb:jobs

An app's durable jobs: a queue of one-off jobs and named recurring ones in one record. A job names a path of the app that runs it. Delivery can repeat, so a handler uses the job's id to stay idempotent. A job has MAX_ATTEMPTS attempts, retried after 1 s, then 2 s; a claim holds a LEASE_MS lease, so the job of a worker that died is claimed again. Every change is a compare-and-set on the record, so two workers never settle one claim.

gizlang
import * as Jobs from "gizweb:jobs";

Types

Job

gizlang
type Job = { @Key id: string; path: string; payload: string; due: i64; @Column("interval_ms") intervalMs: i64; attempts: i64; state: string; lease: i64; error: string; }

One job. due is when it may run (ms); lease is when the running claim ends; a recurring job has intervalMs.

  • id: string
  • path: string
  • payload: string
  • due: i64
  • intervalMs: i64
  • attempts: i64
  • state: string — pending, running, done or failed.
  • lease: i64
  • error: string

Functions

install

gizlang
function install(d: Data.Db): bool throws Model.Rejection

Makes the jobs table when it is not there.

Effects: fail, read, write, console, io.

enqueue

gizlang
function enqueue(d: Data.Db, id: string, path: string, payload: string, due: i64): bool throws Model.Rejection

Queues a job of PATH with PAYLOAD under the fresh ID, due at DUE.

Effects: fail, read, write, console, io.

schedule

gizlang
function schedule(d: Data.Db, name: string, path: string, interval: i64, due: i64): bool throws Model.Rejection

Runs PATH every INTERVAL ms under the job id "schedule:NAME", first at DUE. A second call changes its path and interval and keeps its state.

Effects: fail, read, write, console, io.

next

gizlang
function next(d: Data.Db): Option<i64> throws Model.Rejection

When the next job is due or its lease ends, so a worker sleeps until then; none when no job waits. A running job whose attempts are spent counts too: its claimant finalizes it.

Effects: fail, read, write, console, io.

claim

gizlang
function claim(d: Data.Db, now: i64): Option<Job> throws Model.Rejection

Claims the job that is due first at NOW, if any, with a fresh lease. A running job whose lease ended and whose attempts are spent ends here: failed, or, when it recurs, due again one interval later.

Effects: fail, read, write, console, io.

finish

gizlang
function finish(d: Data.Db, job: Job, error: string, now: i64): bool throws Model.Rejection

Settles the claim JOB at NOW: done, or, with an ERROR, due again until its attempts are spent. A recurring job is due again one interval after its last due time. False when JOB is no longer the current claim.

Effects: fail, read, write, console, io.

Constants

MAX_ATTEMPTS

gizlang
const MAX_ATTEMPTS = 3

The runs a job gets before it fails for good.

LEASE_MS

gizlang
const LEASE_MS = 30000

How long a claim holds a job before another worker may take it again.