Runic.Runner.Store behaviour (Runic v0.1.0-alpha.7)

Copy Markdown View Source

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

cursor()

@type cursor() :: non_neg_integer()

event()

@type event() :: struct()

log()

@type log() :: [struct()]

state()

@type state() :: term()

workflow_id()

@type workflow_id() :: term()

Callbacks

append(workflow_id, events, state)

(optional)
@callback append(workflow_id(), events :: [event()], state()) ::
  {:ok, cursor()} | {:error, term()}

checkpoint(workflow_id, log, state)

(optional)
@callback checkpoint(workflow_id(), log(), state()) :: :ok | {:error, term()}

delete(workflow_id, state)

(optional)
@callback delete(workflow_id(), state()) :: :ok | {:error, term()}

exists?(workflow_id, state)

(optional)
@callback exists?(workflow_id(), state()) :: boolean()

init_store(opts)

@callback init_store(opts :: keyword()) :: {:ok, state()} | {:error, term()}

list(state)

(optional)
@callback list(state()) :: {:ok, [workflow_id()]} | {:error, term()}

load(workflow_id, state)

@callback load(workflow_id(), state()) :: {:ok, log()} | {:error, :not_found | term()}

load_fact(fact_hash, state)

(optional)
@callback load_fact(fact_hash :: term(), state()) ::
  {:ok, term()} | {:error, :not_found | term()}

load_snapshot(workflow_id, state)

(optional)
@callback load_snapshot(workflow_id(), state()) ::
  {:ok, {cursor(), binary()}} | {:error, :not_found | term()}

save(workflow_id, log, state)

@callback save(workflow_id(), log(), state()) :: :ok | {:error, term()}

save_fact(fact_hash, value, state)

(optional)
@callback save_fact(fact_hash :: term(), value :: term(), state()) ::
  :ok | {:error, term()}

save_snapshot(workflow_id, cursor, snapshot, state)

(optional)
@callback save_snapshot(workflow_id(), cursor(), snapshot :: binary(), state()) ::
  :ok | {:error, term()}

stream(workflow_id, state)

(optional)
@callback stream(workflow_id(), state()) ::
  {:ok, Enumerable.t()} | {:error, :not_found | term()}

Functions

supports_stream?(store_mod)

@spec supports_stream?(module()) :: boolean()

Returns true if the store module supports event-sourced stream semantics.