Oban worker that wraps a CouncilEx run in a durable, retry-safe
job.
Execution semantics:
- Job survives node restarts. Any node in the cluster can pick it up — the work runs on whichever node Oban schedules.
timeout/1returns:infinitybecause council runs commonly exceed Oban's 1-minute default. If a hard cap is needed, override via your application's worker (see "Subclassing" below).- Worker calls
CouncilEx.run/3(which usesstart_link/3internally), so a worker timeout / kill propagates to the run — runner dies with the worker, no orphan tokens. - Each retry receives a new
run_id(per-attempt). The original is stored on the run row as:parent_attempt_run_idso the chain is reconstructable.
Args
Job args is a map with:
"council"— string. Module name (Module.splitform) or"dynamic:<id>". Looked up viaString.to_existing_atom/1so the module must be loaded on every replica."input"— arbitrary JSON. Passed verbatim toCouncilEx.run/3."run_id"— string. The id assigned byCouncilEx.start/3for the first attempt. On retries the worker generates a new id and links it via:parent_attempt_run_id.
Subclassing
If you need a custom queue, max attempts, or args schema, define your own worker that delegates:
defmodule MyApp.CouncilWorker do
use Oban.Worker, queue: :councils, max_attempts: 3
@impl true
def timeout(_), do: :timer.minutes(30)
@impl true
def perform(job), do: CouncilEx.Workers.Oban.perform(job)
end