Raxol.Workflow.Runtime (Raxol v2.8.0)

View Source

Execution runtime for Raxol.Workflow.Compiled graphs.

Implements the synchronous invoke/3 and resume/4 paths. Walks the graph from :__start__ to :__end__, executes each node according to its descriptor type, dispatches any returned directives through Raxol.Core.Runtime.Directive.Executor, and emits per-node telemetry with full trace context (trace_id, span_id, parent_span_id, causation_id) propagated through TraceContext.

Capabilities

  • Per-attempt span + telemetry, with retry under failure_policy: :retry (configurable max_attempts and retry_backoff_ms).
  • Saga-style compensation under failure_policy: :compensate, walking executed nodes in reverse and emitting node.compensated events.
  • Optional Checkpoint.Saver-backed durability. Fresh runs pre-checkpoint the initial state at step 0 so resumes work even when the very first node interrupts.
  • Human-in-the-loop pauses via Workflow.interrupt/1 and Compiled.resume/4.

Async wrappers (async_invoke, stream_events, async_resume, resume_events) live in Raxol.Workflow.Async. Conditional fan-out branches run concurrently and reconverge through add_join/4; channel reducers merge branch state before the join node executes.

Summary

Functions

Generate a fresh 16-character hex run id.

Run the compiled graph synchronously.

Look up the latest checkpoint for run_id via the configured Saver, without applying it. Used by Raxol.Workflow.Async to surface resume preconditions synchronously before spawning a worker.

Resume an interrupted run from its latest checkpoint.

Types

result()

@type result() ::
  {:ok, state :: any(), meta :: map()}
  | {:interrupted, run_id :: binary(), state :: any(), value :: any()}
  | {:error, reason :: any(), state :: any()}

Functions

generate_run_id()

@spec generate_run_id() :: binary()

Generate a fresh 16-character hex run id.

invoke(compiled, initial_state, opts \\ [])

@spec invoke(Raxol.Workflow.Compiled.t(), any(), keyword()) :: result()

Run the compiled graph synchronously.

opts may include :run_timeout_ms (default 60_000) to bound the total wall-clock time.

nodes_executed counts each user node once after its retries settle, including nodes in concurrent branches. Checkpoint step addresses use separate branch strides and are never reported as execution progress.

Returns one of:

  • {:ok, final_state, %{run_id, nodes_executed}}
  • {:interrupted, run_id, state, value} when a node returns {:interrupt, value}
  • {:error, reason, state} on node failure, raised exception, or walltime exceeded

preflight_resume(compiled, run_id)

@spec preflight_resume(Raxol.Workflow.Compiled.t(), binary()) ::
  {:ok, Raxol.Workflow.Checkpoint.t()}
  | {:error, :no_saver_configured | :no_checkpoint}

Look up the latest checkpoint for run_id via the configured Saver, without applying it. Used by Raxol.Workflow.Async to surface resume preconditions synchronously before spawning a worker.

Returns {:ok, checkpoint} when a checkpoint is found, {:error, :no_saver_configured} when the graph has no Saver, or {:error, :no_checkpoint} when no checkpoint exists for run_id.

resume(compiled, run_id, resume_value, opts \\ [])

@spec resume(Raxol.Workflow.Compiled.t(), binary(), any(), keyword()) ::
  result() | {:error, :no_saver_configured | :no_checkpoint, nil}

Resume an interrupted run from its latest checkpoint.

Reads the latest checkpoint for run_id via the configured Saver, hydrates the state, seeds the scratchpad with resume_value, and continues execution from the node after the checkpoint's node (which is the node that interrupted on the prior run). Re-invokes interrupt/1 from inside that node returns the resume value instead of throwing.

Returns the same result tuple shape as invoke/3.

Errors

  • {:error, :no_saver_configured, nil} when the graph has no Saver
  • {:error, :no_checkpoint, nil} when the thread has no recorded checkpoints