CouncilEx.RunServer (CouncilEx v0.1.0)

Copy Markdown View Source

GenServer that drives a single council run from start to finish.

Public surface

Most callers should use CouncilEx.start/3 (unsupervised, mirrors GenServer.start/3) or CouncilEx.start_link/3 (linked, mirrors GenServer.start_link/3). Both return {:ok, pid}. Fetch the auto-generated run_id from the pid via CouncilEx.RunServer.run_id/1 if needed.

For tenant isolation or bulk-terminate semantics, use CouncilEx.Supervisor to group runs under a caller-owned DynamicSupervisor.

Direct start_link/1 is supported for callers who want to embed run servers under their own custom supervision tree. Required opts:

  • :run_id — string identifier (typically generated by CouncilEx.start/3; pass any unique binary if starting manually).
  • :council — council id (a module or "dynamic:" <> id).
  • :spec%CouncilEx.Spec{} produced by mod.__council__() or CouncilEx.DynamicCouncil.to_spec/1.
  • :input — the run input (any term).

Optional opts:

  • :user_opts — keyword list forwarded to the runner (e.g. :verbose, retry tuning, etc.). Defaults to [].
  • :callers$callers chain to inherit (set automatically when called from a process that already has one).

The process registers under CouncilEx.Runner.Registry keyed by run_id. PubSub events are broadcast on "council_ex:run:" <> run_id.

Summary

Types

Stable curated subset of run state.

Functions

Returns a specification to start this module under a supervisor.

Default registry used when :registry opt is not passed.

Look up the pid serving run_id. Returns {:error, :unknown_run} when nothing is registered, {:error, :runner_dead} when the registry holds a stale entry whose process has exited (rare; the Registry normally cleans these up automatically).

Fetch the run_id from a runner pid.

Start a RunServer unsupervised and unlinked.

Start a RunServer linked to the calling process.

Curated read of run state for diagnostics.

Build a via tuple keyed by run_id under the bundled registry.

Types

run_summary()

@type run_summary() :: %{
  run_id: binary(),
  council: module(),
  status: :pending | :running | :completed | :failed | :cancelled,
  current_round: %{name: atom(), idx: non_neg_integer()} | nil,
  rounds_completed: non_neg_integer(),
  started_at: DateTime.t()
}

Stable curated subset of run state.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

default_registry()

@spec default_registry() :: atom()

Default registry used when :registry opt is not passed.

Override via app config:

config :council_ex, :runner_registry, MyApp.RunReg

fetch_result(run_id, timeout \\ 5000, opts \\ [])

pid_for(run_id, opts \\ [])

@spec pid_for(
  binary(),
  keyword()
) :: {:ok, pid()} | {:error, :unknown_run | :runner_dead}

Look up the pid serving run_id. Returns {:error, :unknown_run} when nothing is registered, {:error, :runner_dead} when the registry holds a stale entry whose process has exited (rare; the Registry normally cleans these up automatically).

Pass :registry in opts for caller-owned registries.

run_id(pid)

@spec run_id(pid()) :: String.t()

Fetch the run_id from a runner pid.

start(opts)

@spec start(keyword()) :: GenServer.on_start()

Start a RunServer unsupervised and unlinked.

Mirrors GenServer.start/3. The runner has no parent — caller is responsible for the pid. Lose the reference and you have a leak.

Most consumers should call CouncilEx.start/3 rather than this directly.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Start a RunServer linked to the calling process.

Mirrors GenServer.start_link/3. The runner is registered under a Registry (default CouncilEx.Runner.Registry, override via :registry) keyed by run_id.

Use this when the caller owns the run's lifecycle — caller dies, run dies. Most consumers should call CouncilEx.start_link/3 rather than this directly; this is the supervisor-friendly entry point used by CouncilEx.Supervisor.start_link/4 and any caller-owned DynamicSupervisor child spec.

state(run_id, opts \\ [])

@spec state(
  binary(),
  keyword()
) :: {:ok, run_summary()} | {:error, :not_found}

Curated read of run state for diagnostics.

Returns {:ok, run_summary()} for an active or recently-completed run, or {:error, :not_found} if the run id isn't registered.

via_tuple(run_id, opts \\ [])

@spec via_tuple(
  binary(),
  keyword()
) :: {:via, atom(), {atom(), binary()}}

Build a via tuple keyed by run_id under the bundled registry.

Useful for GenServer.call/2 against a known run id.

Pass :registry in opts for caller-owned registries.