Behaviour for workflow persistence adapters.
Adapters handle saving and loading workflow event logs for durability across process restarts.
Stream Semantics (Event-Sourced)
The preferred interface uses append/3 and stream/2 for incremental
event persistence. Events are appended after each execution cycle and
streamed on recovery to rebuild workflow state via Workflow.from_events/1.
Stores that implement append/3 and stream/2 get automatic
event-sourced checkpointing and recovery from the Worker.
Legacy Semantics (Snapshot)
The save/3 and load/2 callbacks persist the full workflow log as a
snapshot. These remain the required baseline interface for backward
compatibility. Stores that only implement save/load continue to work
unchanged.
Optional Capabilities
- Snapshots (
save_snapshot/4,load_snapshot/3): Point-in-time workflow snapshots for faster recovery (replay from snapshot + events after cursor instead of full replay). - Fact storage (
save_fact/3,load_fact/2): Content-addressed fact value storage for hybrid rehydration without loading all values into memory.
Summary
Functions
Returns true if the store module supports event-sourced stream semantics.
Types
@type cursor() :: non_neg_integer()
@type event() :: struct()
@type log() :: [struct()]
@type state() :: term()
@type workflow_id() :: term()
Callbacks
@callback append(workflow_id(), events :: [event()], state()) :: {:ok, cursor()} | {:error, term()}
@callback checkpoint(workflow_id(), log(), state()) :: :ok | {:error, term()}
@callback delete(workflow_id(), state()) :: :ok | {:error, term()}
@callback exists?(workflow_id(), state()) :: boolean()
@callback list(state()) :: {:ok, [workflow_id()]} | {:error, term()}
@callback load(workflow_id(), state()) :: {:ok, log()} | {:error, :not_found | term()}
@callback load_snapshot(workflow_id(), state()) :: {:ok, {cursor(), binary()}} | {:error, :not_found | term()}
@callback save(workflow_id(), log(), state()) :: :ok | {:error, term()}
@callback save_snapshot(workflow_id(), cursor(), snapshot :: binary(), state()) :: :ok | {:error, term()}
@callback stream(workflow_id(), state()) :: {:ok, Enumerable.t()} | {:error, :not_found | term()}