GenDurable (gen_durable v0.1.2)

Copy Markdown View Source

Durable FSM engine on top of Postgres + GenServer.

Start the engine in a host supervision tree:

{GenDurable, repo: MyApp.Repo, queues: [default: 10, checkout: 5]}

FSMs are resolved from the row (the fsm column defaults to the module name); pass :fsms only for a custom :name or to keep an old :version running.

Then enqueue instances and deliver signals:

{:ok, id} = GenDurable.insert(Checkout, state: %{order: 42}, partition_key: "order:42")
:ok = GenDurable.signal(id, "payment_confirmed", %{amount: 100}, dedup_key: "evt-7")

Telemetry

Attach to these :telemetry events ([:gen_durable, …]):

  • [:gen_durable, :step, :stop] — a step finished. Measurements %{duration} (native units); metadata %{id, fsm, step, kind} where kind is the outcome (:next · :replay · :await · :schedule_childs · :done · :stop).
  • [:gen_durable, :pick, :stop] — a picker batch ran. Measurements %{count, demand}; metadata %{queue, worker}. Watch count vs demand to see how full picks are.
  • [:gen_durable, :scheduler, :saturation] — per-poll gauge. Measurements %{in_flight, buffer, concurrency, prefetch}; metadata %{queue}. The signal for tuning the feeder knobs.
  • [:gen_durable, :scheduler, :drain] — graceful shutdown of a queue. Measurements %{released, in_flight}; metadata %{queue}.
  • [:gen_durable, :partition, :contended] — a partition advisory lock was contended (a row was handed back). Measurements %{count}; metadata %{id, fsm, partition_key}.
  • [:gen_durable, :reaper, :reaped] — expired leases reclaimed. Measurements %{count}; metadata %{ids}.

See gen_durable_spec.md (normative) and gen_durable_plan.md (roadmap).

Summary

Functions

Enqueue one FSM instance. Options: :state (alias :args, the job-form name), :step (default the FSM's :initial), :queue, :priority, :partition_key, :unique_key, :unique_scope, and scheduling — :eligible_at (a DateTime), or the sugar :schedule_at (a DateTime) / :schedule_in (milliseconds from now). Returns {:ok, id} or {:error, :duplicate}.

Batch-enqueue instances in a single statement (dedup via the partial unique index). entries is a list of per-instance option keyword lists. Returns the list of inserted ids (duplicates dropped).

Deliver a durable signal to an instance (spec §5). Wakes the instance only on a name match. :dedup_key (default nil) makes redelivery idempotent.

Functions

child_spec(opts)

insert(fsm_module, opts \\ [])

Enqueue one FSM instance. Options: :state (alias :args, the job-form name), :step (default the FSM's :initial), :queue, :priority, :partition_key, :unique_key, :unique_scope, and scheduling — :eligible_at (a DateTime), or the sugar :schedule_at (a DateTime) / :schedule_in (milliseconds from now). Returns {:ok, id} or {:error, :duplicate}.

insert_all(fsm_module, entries, opts \\ [])

Batch-enqueue instances in a single statement (dedup via the partial unique index). entries is a list of per-instance option keyword lists. Returns the list of inserted ids (duplicates dropped).

signal(target_id, name, payload \\ %{}, opts \\ [])

Deliver a durable signal to an instance (spec §5). Wakes the instance only on a name match. :dedup_key (default nil) makes redelivery idempotent.

start_link(opts)

See GenDurable.Supervisor.start_link/1.