Help us shape the future of Go! Take the 2026 Go Developer Survey

engine

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ComponentVarsReporter added in v0.2.0

type ComponentVarsReporter interface {
	ComponentVars(componentKey string, vars map[string]cty.Value)
}

ComponentVarsReporter is implemented by reporters that keep run records. The engine passes it each component's resolved inputs (its var.* namespace, keyed like ParsedScenario.Components) before the component's first action runs, so teardown can evaluate the component's teardown bodies against the same values. Inputs holding a sensitive value carry parser.SensitiveMark.

type Engine

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

Engine executes a scenario's dependency graph.

func New

func New(registry *provider.Registry) (*Engine, error)

New constructs an Engine over the given provider registry. It also builds the action-type routing table, failing if two providers declare the same action name — that ambiguity must be resolved by the caller (via an explicit provider choice in the scenario, coming in a later milestone) before execution can proceed.

The engine installs a NopReporter by default. Call SetReporter to receive progress events.

func (*Engine) Execute

func (e *Engine) Execute(ctx context.Context, ps *parser.ParsedScenario, g *graph.Graph) (*Result, error)

Execute runs every node once its dependencies have completed, up to SetParallelism actions at a time, and returns scenario outputs.

The calling goroutine is the coordinator: it owns resolved outputs, component inputs and counters, builds each action's eval context before handing it to a goroutine, and makes every reporter call, so reporters need no locking. Ready nodes are dispatched in g.Order order, so parallelism 1 runs exactly g.Order. After the first failure nothing new starts, but ctx isn't cancelled: actions in flight finish, so their side effects and undos reach the record.

func (*Engine) Hints

func (e *Engine) Hints() []string

Hints returns the non-fatal hints planners reported during the last ValidateReferences, each prefixed with its action and location.

func (*Engine) PlannedAttrs

func (e *Engine) PlannedAttrs(id graph.NodeID) map[string]cty.Value

PlannedAttrs returns an action's attributes as the last ValidateReferences evaluated them: values that depend on other actions are unknown. Nil unless SetKeepPlannedAttrs is on.

func (*Engine) ResolveProvider

func (e *Engine) ResolveProvider(actionType, providerAlias string) (string, error)

ResolveProvider exposes the engine's action-to-provider routing for tooling (the plan renderer, future "orchard describe" commands). It returns the local alias of the provider that will handle (actionType, providerAlias) or an error when the pair is ambiguous / unknown. providerAlias may be empty when the scenario did not explicitly disambiguate; a unique candidate is returned in that case.

func (*Engine) SetKeepPlannedAttrs

func (e *Engine) SetKeepPlannedAttrs(on bool)

SetKeepPlannedAttrs makes ValidateReferences evaluate every action's attributes, not only those a provider plans, and keep them for PlannedAttrs. `orchard plan --show-values` turns it on.

func (*Engine) SetParallelism

func (e *Engine) SetParallelism(n int)

SetParallelism sets how many independent actions Execute runs at once. The default, 1, runs them one at a time in g.Order.

func (*Engine) SetReporter

func (e *Engine) SetReporter(r Reporter)

SetReporter installs a Reporter for execution events. Call before Execute; there is no synchronization around the reporter field.

func (*Engine) Teardown

func (e *Engine) Teardown(
	ctx context.Context,
	ps *parser.ParsedScenario,
	g *graph.Graph,
	vars map[string]cty.Value,
	compVars map[string]map[string]cty.Value,
	recordedOutputs map[string]map[string]cty.Value,
	undos map[string]provider.Invocation,
	done map[string]bool,
	completed []string,
) ([]string, error)

Teardown undoes each action that succeeded in a prior `orchard run`, in the reverse of the order that run completed them. vars, compVars, recordedOutputs and undos are the state that run captured in its record: the scenario's resolved variables, each component's resolved inputs (keyed like ParsedScenario.Components), each succeeded node's outputs, and the undo invocations providers described, keyed by full node ID ("action.sql.create_merchant" etc.). A component missing from compVars (a record from before they were kept), or whose entry leaves some variables out (sensitive ones), has its inputs evaluated again from vars and recordedOutputs to fill the gaps. Nodes in done were torn down by an earlier, partly failed teardown and are skipped. completed lists node IDs in the order the run completed them (the record's node order); nodes it doesn't name, or all nodes when it is nil, follow in reverse topological order.

For each action, in order of precedence:

  1. its `lifecycle { teardown { } }` body, evaluated and run against its provider;
  2. otherwise its recorded undo invocation (a typed insert's delete by primary key), unless the scenario now says `managed_teardown = false`;
  3. otherwise nothing.

Actions whose original run failed, actions that no longer route to a registered provider, and component nodes are skipped.

Teardown is best-effort: failures on individual actions are logged via the reporter's NodeFailed hook but don't abort the walk. Teardown returns the nodes whose teardown succeeded, so the caller can record them, and the joined set of per-action errors, or nil if every attempted teardown succeeded.

Eval context per action:

  • var.<name> — scenario variables, or for an action inside a component, the component's inputs
  • self.<field> — this action's recorded outputs
  • action.<type>.<name>.<field> — any other action's recorded outputs; inside a component, only the component's own actions

The teardown body is evaluated against the same provider action schema as the outer action, so `lifecycle { teardown { query = "..." } }` on a sql action type-checks against the sql action's `query` attribute declaration.

Note: Teardown accepts pre-decoded cty state rather than the record.Record itself so the engine stays independent of the record package — record imports engine for its Reporter, and we avoid the cycle by making the caller do the decoding with record's own helpers.

func (*Engine) UncheckedProviders

func (e *Engine) UncheckedProviders() []string

UncheckedProviders lists, in order, the providers whose actions the last ValidateReferences couldn't check for want of a schema (no snapshot during `orchard plan`).

func (*Engine) ValidateGraph

func (e *Engine) ValidateGraph(g *graph.Graph) error

ValidateGraph runs structural schema validation on every action node in the graph without executing anything. It catches the errors that are worth surfacing at plan time — unknown attribute names, missing required attributes, and action types that no registered provider handles — while deferring runtime-dependent checks (expression evaluation, type coercion against upstream outputs) to execution.

Safe to call before Configure. The method reads only the routing table built from provider schemas, so providers do not need live connections to validate a plan.

Returns the first error found. A multi-error aggregator would be a natural upgrade once callers start wanting "all problems at once" reporting, but for today the single-error form maps cleanly onto command-line tooling.

func (*Engine) ValidateReferences

func (e *Engine) ValidateReferences(runCtx context.Context, ps *parser.ParsedScenario, g *graph.Graph) error

ValidateReferences type-checks scenario expressions against the declared output shapes of the actions and components they reference. It catches typos in `action.X.Y.Z` references, basic type mismatches (using a number where a string is required), and undeclared variable references — all at plan time, without running a single provider call.

The check walks action bodies (scenario-level ones against the scenario's namespaces, component-internal ones against their component's var namespace and actions), scenario output expressions, component input expressions and component outputs.

Coverage caveat: actions whose provider schema declares `output { type = any }` (e.g. postgres.sql with its open-ended RETURNING shape) are typed as `cty.DynamicPseudoType`, which makes any attribute access legal. Typos on those stay runtime errors. The fix is for providers to declare concrete output shapes where they can; the plan check gets stricter for free when they do.

Providers that implement provider.ActionPlanner also check each of their actions here, against external state such as a database's schema: during `orchard plan` from a snapshot, during `orchard run` (after Configure) against the live system, before any action executes. A planner can report a concrete output type, which then types references to that action's outputs.

Actions are checked in dependency order, inside components as well as at scenario level, so each action sees the output types of the ones before it.

type NopReporter

type NopReporter struct{}

NopReporter discards all events. Engine uses it by default so callers that do not care about progress pay zero cost.

func (NopReporter) NodeCompleted

func (NopReporter) NodeCompleted(string, map[string]cty.Value, time.Duration)

NodeCompleted implements Reporter.

func (NopReporter) NodeFailed

func (NopReporter) NodeFailed(string, error)

NodeFailed implements Reporter.

func (NopReporter) NodeStarted

func (NopReporter) NodeStarted(string)

NodeStarted implements Reporter.

func (NopReporter) RunCompleted

func (NopReporter) RunCompleted(RunSummary)

RunCompleted implements Reporter.

func (NopReporter) RunStarted

func (NopReporter) RunStarted(string)

RunStarted implements Reporter.

type Reporter

type Reporter interface {
	// RunStarted fires once, before any node executes. scenario is
	// the name from the top-level scenario block.
	RunStarted(scenario string)

	// NodeStarted fires just before a node's action runs. Component
	// nodes also emit this so reporters can show component-level
	// progress alongside action progress. The id is the fully-
	// qualified graph node id (e.g. "action.sql.create" or
	// "component.merchant.base").
	NodeStarted(nodeID string)

	// NodeCompleted fires after a node finishes successfully.
	// duration measures wall-clock time spent in the node's own
	// work (action execute, or component output resolution) —
	// upstream wait time is excluded.
	//
	// outputs carries the node's resolved outputs: an action's
	// Execute return map for action nodes, the resolved component
	// outputs for component nodes. Presentation reporters typically
	// ignore it; the recording reporter uses it to persist each
	// node's contribution to a run record.
	NodeCompleted(nodeID string, outputs map[string]cty.Value, duration time.Duration)

	// NodeFailed fires when a node returns an error. The engine
	// returns that error to the caller too; this gives the
	// reporter a chance to present it with context (the node id
	// that failed) before the caller unwinds.
	NodeFailed(nodeID string, err error)

	// RunCompleted fires once, after the last node is done and
	// scenario outputs have been evaluated. ok is false when the
	// run aborted part-way.
	RunCompleted(summary RunSummary)
}

Reporter receives observability events from the engine's execution loop. The engine has no opinion on how events are surfaced — CLI, structured logs, test-silence, or a future TUI all implement this interface. Scenarios can take minutes to run; making this hook pluggable keeps the engine independent of presentation.

All methods are best-effort. The engine never checks return values; Reporter implementations must not block or fail the run. The engine makes every call from one goroutine, even when actions run in parallel, so implementations need no locking.

type Result

type Result struct {
	Outputs map[string]cty.Value
}

Result holds the outputs from executing a scenario.

type RunSummary

type RunSummary struct {
	Scenario  string
	Outputs   map[string]cty.Value
	Duration  time.Duration
	Succeeded int
	Failed    int
	OK        bool
	Err       error // non-nil when the run aborted
}

RunSummary is the end-of-run event payload.

type UndoReporter

type UndoReporter interface {
	NodeUndo(nodeID string, undo provider.Invocation)
}

UndoReporter is implemented by reporters that keep run records. After NodeCompleted, the engine passes it the invocation that undoes the action, when the action's provider described one and the action has no explicit teardown block and hasn't opted out with `managed_teardown = false`.

Jump to

Keyboard shortcuts

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