dag

package
v0.11.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 15, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package dag provides a small action-oriented directed acyclic graph.

Nodes are Nexss actions. Compile validates dependencies and produces deterministic execution layers. Execute runs each layer with cancellation and merges results only at layer boundaries.

Index

Constants

This section is empty.

Variables

View Source
var ErrSuspended = errors.New("graph: execution suspended for human intervention")

ErrSuspended signals that a node has paused execution (e.g. awaiting human approval). Returning this error preserves partial state so it can be saved to persistent storage.

View Source
var GlobalTopology = &TopologyRegistry{}

Functions

func GetNodeOutput

func GetNodeOutput[T any](state *State, nodeID string) (T, error)

GetNodeOutput reads a node result using the allocation-free direct type path.

func OutputKey

func OutputKey(nodeID string) string

OutputKey returns the canonical collision-resistant state key for a node.

func Suspend added in v0.11.1

func Suspend(reason string, payload any) error

Suspend pauses DAG execution gracefully. The returned error matches ErrSuspended.

func WithLayerCallback added in v0.11.0

func WithLayerCallback(ctx context.Context, fn LayerCallback) context.Context

WithLayerCallback attaches a callback to ctx.

Use it to checkpoint the DAG after every layer. A caller that keeps the last successful state, checks that the flow definition has not changed, and re-executes with that state gets resume-from-failure for free: DAG.Execute already skips any node whose output key is present in the initial state, so only the nodes that did not run are re-run.

Types

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

func New

func New(name string) *Builder

func (*Builder) AddEdge

func (b *Builder) AddEdge(from, to string) *Builder

func (*Builder) AddNode

func (b *Builder) AddNode(id string, _ string, act action.AnyAction) *Builder

func (*Builder) Compile

func (b *Builder) Compile() (*DAG, error)

type DAG

type DAG struct {
	// contains filtered or unexported fields
}

func (*DAG) AsAction

func (d *DAG) AsAction() *action.Builder[*State, *State]

AsAction wraps the DAG execution as a standard Nexss Action.

func (*DAG) Execute

func (d *DAG) Execute(ctx context.Context, initialState *State) (*State, error)

Execute runs DAG layers sequentially, executing nodes in each layer concurrently. Supports HIL resumption: nodes whose output key is already present in initialState are skipped.

A LayerCallback may be attached to ctx with WithLayerCallback; when present it is invoked after each layer with the state that already includes that layer's outputs. A callback error aborts execution and is returned wrapped in *ExecutionError, unless the callback returned ErrSuspended, in which case the sentinel is preserved.

On any error the returned state is non-nil and owns every node output produced so far. The caller must Release it.

The callback is consumed by the outermost DAG that sees it, so nested DAGs never fire it twice.

func (*DAG) Name added in v0.3.2

func (d *DAG) Name() string

func (*DAG) ToMermaid added in v0.3.1

func (d *DAG) ToMermaid() string

ToMermaid exports the compiled DAG topology to Mermaid flowchart syntax. It is deterministic, safe for concurrent calls, and allocation-optimized.

type Edge

type Edge struct {
	From string
	To   string
}

type EdgeMeta

type EdgeMeta struct {
	From     string
	To       string
	Channel  string
	Protocol string
}

type ExecutionError added in v0.11.0

type ExecutionError struct {
	Layer      int
	FailedNode string
	Cause      error
	State      *State
	Completed  []string
}

ExecutionError reports that a layer stopped before every node in it succeeded. State carries the partial result: every node whose output is present already ran, so a caller that persists State and later re-executes with it will re-run only the missing nodes.

The caller owns State and must call Release on it, exactly as with a successful return.

func (*ExecutionError) Error added in v0.11.0

func (e *ExecutionError) Error() string

func (*ExecutionError) Unwrap added in v0.11.0

func (e *ExecutionError) Unwrap() error

type LayerCallback added in v0.11.0

type LayerCallback func(ctx context.Context, layer int, state *State) error

LayerCallback is invoked by DAG.Execute after each layer completes.

The state passed to the callback already includes every node output from the completed layer. A callback error aborts execution and is returned to the caller; the state at the point of failure is preserved, not released, so the caller can inspect or persist it.

Nested DAGs do not fire the callback. The outermost DAG that finds a callback in its context consumes it, and every nested DAG in the same execution tree sees an empty slot. This makes the callback a checkpoint hook for one top-level execution, not for every graph in the tree.

func LayerCallbackFromCtx added in v0.11.0

func LayerCallbackFromCtx(ctx context.Context) LayerCallback

LayerCallbackFromCtx returns the callback attached by WithLayerCallback. It returns nil when no callback is set, and also when the callback has already been consumed by an outer DAG.Execute.

type Node

type Node struct {
	ID        string
	OutputKey string
	Action    action.Executable
}

type NodeContext

type NodeContext struct {
	// Input is the read-only, frozen state from preceding layers.
	//
	// ⚠️ WARNING: Because DAG state utilizes sync.Pool for memory efficiency,
	// you MUST NOT read from Input after your node's handler function returns.
	// Spawning detached goroutines that access Input beyond the lifecycle of
	// this function will result in use-after-free panics or silent data corruption
	// when the state is recycled and reused by subsequent graph executions.
	Input *State
	Key   string // Designated output key for this node
}

NodeContext provides execution context to a DAG node.

type State

type State struct {
	// contains filtered or unexported fields
}

State is an immutable-by-convention view of graph state.

func AcquireState

func AcquireState() *State

AcquireState retrieves a State instance from the memory pool.

func (*State) Clone

func (s *State) Clone() *State

Clone creates a new State snapshot.

func (*State) CopyFrom

func (s *State) CopyFrom(src *State)

CopyFrom populates s with src data, guaranteeing independent map headers.

func (*State) Data

func (s *State) Data() map[string]any

Data exposes the internal map for serialization / rendering.

func (*State) Get

func (s *State) Get(key string) (any, bool)

Get performs a ZERO-LOCK read.

func (*State) Release

func (s *State) Release()

Release clears references and returns the State to the pool.

func (*State) Set

func (s *State) Set(key string, val any)

Set writes a key-value pair to the state.

type SuspendError added in v0.11.1

type SuspendError struct {
	Reason  string
	Payload any
}

SuspendError carries the reason and payload for a graceful pause. Reason is human-readable; Payload is what the approver needs to see.

func (*SuspendError) Error added in v0.11.1

func (e *SuspendError) Error() string

func (*SuspendError) Is added in v0.11.1

func (e *SuspendError) Is(target error) bool

type TopologyRegistry

type TopologyRegistry struct {
	// contains filtered or unexported fields
}

func (*TopologyRegistry) Register

func (t *TopologyRegistry) Register(from, to, channel, protocol string)

func (*TopologyRegistry) ToMermaid

func (t *TopologyRegistry) ToMermaid() string

type Value

type Value struct {
	Key string
	Val any
}

Value holds a key-value output produced by a node.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL