Raxol.Workflow.Runtime (Raxol v2.6.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. Joins (add_join/4) and channel reducers (add_channel/4) are still follow-ups: the runtime is single-branch sequential today.

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. 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