Skip to content

Scheduler

imbi-scheduler triggers remote execution on a schedule. It runs on port 8005 and is served under /scheduler in the all-in-one image.

The scheduler triggers; it does not execute work. Every run is a single synchronous HTTP call, and the outcome is recorded. Two target kinds cover the platform:

Target Goes to Runs as
api imbi-api the scheduler's service account. A delegated user is phase 2: such a task is stored, but every firing is skipped until the exchange grant lands
gateway imbi-gateway nothing — the endpoint has no bearer check and derives attribution from the payload

Long-running work, agentic execution, and rule evaluation belong to whichever service owns them. The scheduler pokes that service and records what came back.

How a run happens

  1. A trigger comes due. The claiming query (FOR UPDATE SKIP LOCKED over scheduler.tasks) gives exactly one replica the claim: concurrent replicas receive disjoint task sets, and the claiming transaction advances next_run_at before committing. That bounds the claim, not delivery — execution is at-most-once, so see ADR 0001.
  2. The task's identity is resolved at fire time, never at creation time. A service_account task uses the scheduler's own client credential; a delegated_user task will exchange that credential for a short-lived token scoped to the target user, once imbi-api implements the exchange grant — until then such a task is stored but every firing is skipped (ADR 0003). gateway targets skip this step.
  3. The target is rendered. path, body, query, and header values are Jinja2 templates over {now, task, run, last_run}, matching the templating model imbi-automations uses so operators learn it once.
  4. One HTTP call, bounded by the task's timeout, retried per its policy.
  5. The result is classified and written to imbi.scheduler_runs in ClickHouse.

A failure to resolve identity is a skipped run, not a failed one, and it does not consume retries — consent that has been revoked should stop a task quietly rather than look like an outage.

Stores

Data Where
Task definitions, trigger state Postgres, schema scheduler
Run history ClickHouse, imbi.scheduler_runs
Consent for delegated tasks The graph, owned by imbi-api. The scheduler stores only a consent_id

The scheduler stores no secrets. See ADR 0002.

Relationship to pg_cron

Both are kept, deliberately. pg_cron is the system-level, in-database operations tool; it runs SQL. imbi-scheduler is the user-level tool; it calls endpoints and carries an identity. No overlap, no migration.

Design decisions

The imbi-api side of delegated execution is ADR 0016.