# Jobs run on the cron tick and a leased queue

The repository's architectural decision, rationale and consequences.

# Jobs run on the cron tick and a leased queue

**Status:** accepted · **Date:** 2026-11-06 · **Related:** [ADR-0005](0005-effect-boundary.md), [ADR-0006](0006-effect-persisted-queue.md)

**Enforcement:** the existing job-runner tests and `scripts/jobs-database.test.mjs`; each new job adds its own test.

The ARD uses pg-boss on Postgres for the nightly k ≥ 20 aggregation, campaign delivery, report PDF/CSV and list publishing. pg-boss needs a long-lived Node process holding connections and its own schema; a Worker has neither.

## Decision [#decision]

1. **Use the template's mechanism**: a Cron Trigger calls the job runner on a tick, and work that must survive failures goes through the persisted, leased queue of [ADR-0006](0006-effect-persisted-queue.md). A worker claims a row with a lease; an expired lease makes the row claimable again; handlers are idempotent.
2. **No pg-boss, no Cloudflare Queues for these jobs.** One queue, in the database we already run, with the tests we already have.
3. **Varu's jobs are**: nightly district aggregation (only districts with ≥ 20 homes, % rounded to 1 point), campaign delivery, report generation and list publishing.

## Consequences [#consequences]

- Latency is bounded by the tick interval; none of these jobs is interactive.
- Throughput is modest and enough: the household app sends almost nothing.
- If volume outgrows the tick, Cloudflare Queues or Workflows can replace the transport without changing handlers.

