Raxol. Workflow. Graph
(Raxol v2.6.0)
View Source
Immutable graph builder for Raxol.Workflow.
Build a graph by piping add_node/3, add_edge/3,
add_guarded_edge/4, add_conditional_edge/4 (and the upcoming
add_join/4 / add_channel/4) onto a new/1 seed, then freeze with
compile/2.
Example
alias Raxol.Workflow.Graph
{:ok, compiled} =
Graph.new(:summarizer)
|> Graph.add_node(:fetch, fn s -> {:ok, Map.put(s, :data, "x")} end)
|> Graph.add_node(:render, fn s -> {:ok, Map.put(s, :rendered, true)} end)
|> Graph.add_edge(:__start__, :fetch)
|> Graph.add_edge(:fetch, :render)
|> Graph.add_edge(:render, :__end__)
|> Graph.compile()Reserved node ids
:__start__-- virtual entry node, present in every graph:__end__-- virtual exit node, present in every graph
Authors must add at least one edge from :__start__ and at least
one edge into :__end__. compile/2 enforces these rules along
with reachability and absence-of-orphans.
Summary
Functions
Declare a typed reducer for a state-map key.
Add a conditional fan-out edge from from. The chooser receives
the state and returns the next node id (or a list of ids for
parallel fan-out). candidates declares the set of possible
destinations so compile/2 can validate them.
Add a static edge from from to to.
Add a guarded edge from from to to. The guard receives the
workflow state; the edge is taken only when the guard returns truthy.
Mark target as a join (barrier) node fed by the listed upstream
branches.
Add a node to the graph. The body argument selects the node shape
Add a FunctionNode with an optional compensation function.
Freeze the graph for execution.
Construct a new, empty graph with the given id.
Types
@type t() :: %Raxol.Workflow.Graph{ channels: %{required(atom() | binary()) => Raxol.Workflow.Channel.t()}, edges: [Raxol.Workflow.Edge.t()], id: atom() | binary(), nodes: %{required(Raxol.Workflow.Node.id()) => Raxol.Workflow.Node.t()} }
@type validation_error() :: {:missing_start_edge, atom()} | {:missing_end_edge, atom()} | {:unknown_node, [Raxol.Workflow.Node.id()]} | {:orphan_nodes, [Raxol.Workflow.Node.id()]} | {:unreachable_from_start, [Raxol.Workflow.Node.id()]} | {:cannot_reach_end, [Raxol.Workflow.Node.id()]} | {:join_target_unknown, Raxol.Workflow.Node.id()} | {:join_upstream_unknown, Raxol.Workflow.Node.id(), [Raxol.Workflow.Node.id()]} | {:join_upstream_shared, [Raxol.Workflow.Node.id()]} | {:join_target_unknown, Raxol.Workflow.Node.id()} | {:join_upstream_unknown, Raxol.Workflow.Node.id(), [Raxol.Workflow.Node.id()]} | {:join_upstream_shared, Raxol.Workflow.Node.id(), [Raxol.Workflow.Node.id()]}
Functions
Declare a typed reducer for a state-map key.
Channels are metadata only -- no nodes or edges are added. At a
join, the runtime applies each channel's with reducer pairwise
across all branch contributions to the channel's into key.
Options:
:into-- the state-map key the reducer writes to. Required.:with-- a 2-arity reducer(left, right) -> merged. Required.
Channel names must be unique within a graph.
@spec add_conditional_edge( t(), Raxol.Workflow.Node.id(), [Raxol.Workflow.Node.id()], (any() -> any()) ) :: t()
Add a conditional fan-out edge from from. The chooser receives
the state and returns the next node id (or a list of ids for
parallel fan-out). candidates declares the set of possible
destinations so compile/2 can validate them.
@spec add_edge(t(), Raxol.Workflow.Node.id(), Raxol.Workflow.Node.id()) :: t()
Add a static edge from from to to.
@spec add_guarded_edge( t(), Raxol.Workflow.Node.id(), Raxol.Workflow.Node.id(), (any() -> any()) ) :: t()
Add a guarded edge from from to to. The guard receives the
workflow state; the edge is taken only when the guard returns truthy.
@spec add_join(t(), Raxol.Workflow.Node.id(), [Raxol.Workflow.Node.id()], keyword()) :: t()
Mark target as a join (barrier) node fed by the listed upstream
branches.
The runtime holds at the join until every node id in upstream has
committed a result on the same run. It then merges each branch's
terminal state (per any declared add_channel/3 reducer; last-write-wins
by branch order for keys without a channel), runs the target node's
body once with the merged state, and continues from target's outgoing
edges.
Options:
:reduce-- explicit(list_of_branch_states -> merged_state)that overrides per-channel + last-write-wins. Default: nil.:timeout_ms-- max wall-clock to wait for all branches before failing with{:branch_timeout, missing}. Default: inherits the run's:run_timeout_ms.:parallelism-- branch execution concurrency.:branches(default) runs every branch concurrently viaTask.async_stream. A positive integer capsmax_concurrency(1selects the serial path, useful when consumers need branch-index-order side effects).
compile/2 validates that target and every upstream id refer to
declared nodes.
@spec add_node(t(), Raxol.Workflow.Node.id(), term()) :: t()
Add a node to the graph. The body argument selects the node shape:
- A 1-arity function builds a
FunctionNode. - A
{module, opts}tuple builds aBehaviourNode. - A struct builds a
TypedNode.
@spec add_node(t(), Raxol.Workflow.Node.id(), (any() -> any()), (any() -> {:ok, any()} | {:error, any()})) :: t()
Add a FunctionNode with an optional compensation function.
Convenience for add_node/3 |> Node.function/3. The
compensate_fun runs in reverse order under
failure_policy: :compensate when the run errors after this node
succeeded. It receives the current state and returns
{:ok, new_state} | {:error, reason}.
@spec compile( t(), keyword() ) :: {:ok, Raxol.Workflow.Compiled.t()} | {:error, validation_error()}
Freeze the graph for execution.
Runs the full validation pipeline (no orphan nodes, every node
reachable from :__start__, every node has a path to :__end__,
conditional candidates exist in the graph) and returns a
Raxol.Workflow.Compiled struct or a structured error.
Options
:failure_policy-- one of:retry,:halt,:compensate(default:halt):max_attempts-- when:failure_policyis:retry, the maximum number of attempts per node (default3). Includes the initial attempt;1disables retries.:retry_backoff_ms-- base backoff delay between retries; each subsequent retry doubles (default100).:step_timeout_ms-- per-node timeout (default60_000):run_timeout_ms-- total run timeout (default3_600_000):saver--Raxol.Workflow.Checkpoint.Savermodule (defaults toEts)
These options are stored on Compiled and consumed by
Raxol.Workflow.Runtime.
Construct a new, empty graph with the given id.