// Package flow is a generic, JSON-configurable orchestration engine. A flow is a // sequence of named steps; each step runs a registered action, may be gated by a // registered predicate, can fire registered hooks (before/after/on-error), and // may declare a compensating action used to roll back on failure (the saga // pattern). Actions, predicates and hooks are registered by name — the same // "interface + interchangeable impls, wired in one place" seam the CMS uses for // its event listeners. The flow definition itself is plain JSON, so flows live // alongside the app's other JSON config (schemas, blueprints) and can be edited // without code changes. package flow import "encoding/json" // Definition is a whole flow, loadable from JSON. type Definition struct { Name string `json:"name"` Description string `json:"description,omitempty"` Steps []Step `json:"steps"` } // Step is one unit of work in a flow. type Step struct { // Name identifies the step in logs, hooks and results. Name string `json:"name"` // Action is the registered action to run. Action string `json:"action"` // Params is opaque JSON passed to the action. Params json.RawMessage `json:"params,omitempty"` // When, if set, names a registered predicate; the step is skipped when it // returns false. When string `json:"when,omitempty"` // Hooks fire around the action. Hooks Hooks `json:"hooks,omitempty"` // Compensate, if set, is the action used to undo this step when a later step // fails (executed in reverse order during rollback). Compensate *ActionRef `json:"compensate,omitempty"` // ContinueOnError records the error and proceeds instead of rolling back. ContinueOnError bool `json:"continueOnError,omitempty"` } // ActionRef names an action and its params (used for compensation). type ActionRef struct { Action string `json:"action"` Params json.RawMessage `json:"params,omitempty"` } // Hooks groups the hook references that fire at each phase of a step. type Hooks struct { Before []HookRef `json:"before,omitempty"` After []HookRef `json:"after,omitempty"` OnError []HookRef `json:"onError,omitempty"` } // HookRef names a registered hook and its params. When, if set, names a // registered predicate; the hook is skipped when it returns false. type HookRef struct { Type string `json:"type"` When string `json:"when,omitempty"` Params json.RawMessage `json:"params,omitempty"` } // Parse loads a flow definition from JSON bytes. func Parse(data []byte) (*Definition, error) { var d Definition if err := json.Unmarshal(data, &d); err != nil { return nil, err } return &d, nil }