Ecto schema for the <prefix>runs table.
One row per (council, attempt) pair. Survives Oban job pruning by
design — :oban_job_id is a plain bigint, not a foreign key. Use
:oban_job_state_at_finalize for post-mortem when the job row is
gone.
Statuses
:queued— job enqueued but not yet picked up:running— recorder has received:run_started:completed—:run_completedevent seen:failed—:run_failedwith non-cancel errors:cancelled—:run_failedcontaining a:cancellederror:stuck— boot-time reconciliation found this row in:runningwith no live Oban job
Retry semantics
Per docs/MULTI_REPLICA_RECORDER.md, each Oban attempt gets a fresh
run_id. The original run id is recorded in
:parent_attempt_run_id to link the chain.
Summary
Functions
Statuses considered active (still consuming resources).
Build a changeset for inserts and updates.
Statuses that indicate the run is no longer active.
Types
@type t() :: %CouncilEx.Persistence.Schema.Run{ __meta__: term(), attempt: term(), council: term(), error: term(), finalized_at: term(), input: term(), inserted_at: term(), oban_job_id: term(), oban_job_state_at_finalize: term(), parent_attempt_run_id: term(), result: term(), run_id: term(), started_at: term(), status: term(), updated_at: term() }
Functions
@spec active_statuses() :: [atom()]
Statuses considered active (still consuming resources).
@spec changeset( t() | %CouncilEx.Persistence.Schema.Run{ __meta__: term(), attempt: term(), council: term(), error: term(), finalized_at: term(), input: term(), inserted_at: term(), oban_job_id: term(), oban_job_state_at_finalize: term(), parent_attempt_run_id: term(), result: term(), run_id: term(), started_at: term(), status: term(), updated_at: term() }, map() ) :: Ecto.Changeset.t()
Build a changeset for inserts and updates.
@spec terminal_statuses() :: [atom()]
Statuses that indicate the run is no longer active.