Documentation
¶
Overview ¶
Package api contains the core building blocks used by the fluxo workflow engine. It provides the low-level primitives for defining workflows, building execution graphs, and observing engine behavior.
Most users interact with the higher-level fluxo package, which re-exports selected types and helpers from this package. The api package is intended for advanced use cases, custom integrations, or contributors extending the engine itself.
Concepts ¶
The api package centers around a small set of concepts:
- Workflow definitions
- Steps and step functions
- Control-flow composition
- Observability
These primitives are assembled by the higher-level FlowBuilder API in the fluxo package, but can also be used directly where fine-grained control is needed.
Workflow Definitions ¶
A workflow definition describes the structure of a workflow: its name, input/output types, and the graph of steps that will be executed.
Definitions are immutable once constructed and are registered with an engine before they can be started. The engine uses these definitions to compute execution plans and to reconstruct the next step to run when a workflow resumes.
Steps and Step Functions ¶
A step represents a single unit of work in a workflow. Steps are backed by step functions, which encapsulate user code. The engine invokes step functions deterministically according to the workflow definition.
Step functions are expected to:
- Be deterministic: same inputs yield the same observable behavior.
- Be idempotent: they may be retried if a worker crashes or a task is rescheduled.
- Modify workflow state through well-defined mechanisms provided by the engine (e.g. updating variables, scheduling timers, sending signals).
Control Flow ¶
The api package defines the core control-flow nodes used to build workflows, including:
- Sequential steps
- Conditionals (if / switch style branching)
- Parallel branches and parallel maps
- Loops (while-style and counted loops)
- Signal waits and timers
These constructs are exposed in a more ergonomic form from the fluxo package, but they are all built from common definitions and step primitives found here.
Typed helpers are available to work with strongly typed inputs and outputs without forcing the caller to manage serialization manually.
Observability ¶
The api package defines the Observer interface, which is used by engines, workers, and runners to report lifecycle events and metrics.
Observers can be used to:
- Log workflow and step transitions
- Collect metrics (e.g. counts, latencies, error rates)
- Integrate with external monitoring systems
The fluxo package exposes ready-made implementations such as logging and basic in-memory metrics, along with helpers to combine multiple observers.
Usage ¶
Most applications should start from the fluxo package, using the FlowBuilder and Engine constructors provided there. The api package is useful when you need lower-level access, custom composition, or when contributing changes to the core engine.
See the fluxo package documentation and the examples directory for end-to-end usage.
Index ¶
- func ContextWithInstance(ctx context.Context, inst *WorkflowInstance) context.Context
- func IsWaitForAnyChildError(err error) bool
- func IsWaitForSignalError(err error) (string, bool)
- func NewWaitForSignalError(name string) error
- func WithEngine(ctx context.Context, e Engine) context.Context
- type BasicMetrics
- func (m *BasicMetrics) OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, idx int, ...)
- func (m *BasicMetrics) OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
- func (m *BasicMetrics) OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
- func (m *BasicMetrics) OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
- func (m *BasicMetrics) Snapshot() BasicMetricsSnapshot
- type BasicMetricsSnapshot
- type ChildWorkflowSpec
- type CompositeObserver
- func (c *CompositeObserver) OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, idx int, ...)
- func (c *CompositeObserver) OnStepStart(ctx context.Context, inst *WorkflowInstance, stepName string, idx int)
- func (c *CompositeObserver) OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
- func (c *CompositeObserver) OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
- func (c *CompositeObserver) OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
- type ConditionFunc
- type Engine
- type InstanceListOptions
- type LoggingObserver
- func (o *LoggingObserver) OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, idx int, ...)
- func (o *LoggingObserver) OnStepStart(ctx context.Context, inst *WorkflowInstance, stepName string, idx int)
- func (o *LoggingObserver) OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
- func (o *LoggingObserver) OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
- func (o *LoggingObserver) OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
- type NoopObserver
- func (NoopObserver) OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, idx int, ...)
- func (NoopObserver) OnStepStart(ctx context.Context, inst *WorkflowInstance, stepName string, idx int)
- func (NoopObserver) OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
- func (NoopObserver) OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
- func (NoopObserver) OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
- type Observer
- type ParallelResult
- type RetryPolicy
- type SelectorFunc
- type SignalPayload
- type Status
- type StepDefinition
- type StepFunc
- func IfStep(cond ConditionFunc, thenStep StepFunc, elseStep StepFunc) StepFunc
- func LoopStep(times int, body StepFunc) StepFunc
- func ParallelMapStep(fn StepFunc) StepFunc
- func ParallelStep(steps ...StepFunc) StepFunc
- func SleepStep(d time.Duration) StepFunc
- func SleepUntilStep(deadline time.Time) StepFunc
- func StartChildrenStep(specsFn func(input any) ([]ChildWorkflowSpec, error)) StepFunc
- func SwitchStep(selector SelectorFunc, branches map[string]StepFunc, defaultStep StepFunc) StepFunc
- func TypedLoop[I any](times int, body func(context.Context, I) (I, error)) StepFunc
- func TypedStep[I, O any](fn func(context.Context, I) (O, error)) StepFunc
- func TypedWhile[I any](cond func(I) bool, body func(context.Context, I) (I, error)) StepFunc
- func WaitForAnyChildStep(getIDs func(input any) []string, pollInterval time.Duration) StepFunc
- func WaitForAnySignalStep(names ...string) StepFunc
- func WaitForChildrenStep(getIDs func(input any) []string, pollInterval time.Duration) StepFunc
- func WaitForSignalStep(name string) StepFunc
- func WhileStep(cond ConditionFunc, body StepFunc) StepFunc
- type TimeoutPayload
- type WaitForAnyChildError
- type WaitForChildrenError
- type WorkflowDefinition
- type WorkflowInstance
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ContextWithInstance ¶
func ContextWithInstance(ctx context.Context, inst *WorkflowInstance) context.Context
func IsWaitForAnyChildError ¶
IsWaitForAnyChildError returns true if the error is WaitForAnyChildError.
func IsWaitForSignalError ¶
IsWaitForSignalError returns (signalName, true) if Err indicates that the step wants to wait for a signal.
func NewWaitForSignalError ¶
NewWaitForSignalError is primarily intended for use by helper step constructors (like WaitForSignalStep), but can be used by custom steps to integrate with the engine's signal semantics.
func WithEngine ¶
WithEngine attaches an Engine to ctx so that StepFunc implementations can discover the engine (for example to start or inspect child workflows).
This is called internally by the engine implementation before invoking step functions.
Types ¶
type BasicMetrics ¶
type BasicMetrics struct {
NoopObserver
// contains filtered or unexported fields
}
BasicMetrics collects simple counters and aggregate step durations. It implements Observer, and can be combined with LoggingObserver via NewCompositeObserver.
func (*BasicMetrics) OnStepCompleted ¶
func (m *BasicMetrics) OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, idx int, err error, d time.Duration)
func (*BasicMetrics) OnWorkflowCompleted ¶
func (m *BasicMetrics) OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
func (*BasicMetrics) OnWorkflowFailed ¶
func (m *BasicMetrics) OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
func (*BasicMetrics) OnWorkflowStart ¶
func (m *BasicMetrics) OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
func (*BasicMetrics) Snapshot ¶
func (m *BasicMetrics) Snapshot() BasicMetricsSnapshot
Snapshot returns a snapshot of the current metrics.
type BasicMetricsSnapshot ¶
type BasicMetricsSnapshot struct {
WorkflowsStarted int64
WorkflowsCompleted int64
WorkflowsFailed int64
PendingWorkflows int64
StepsCompleted int64
AvgStepDuration time.Duration
}
BasicMetricsSnapshot is an immutable snapshot of BasicMetrics.
type ChildWorkflowSpec ¶
type CompositeObserver ¶
type CompositeObserver struct {
// contains filtered or unexported fields
}
CompositeObserver fans out events to multiple observers.
func (*CompositeObserver) OnStepCompleted ¶
func (c *CompositeObserver) OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, idx int, err error, d time.Duration)
func (*CompositeObserver) OnStepStart ¶
func (c *CompositeObserver) OnStepStart(ctx context.Context, inst *WorkflowInstance, stepName string, idx int)
func (*CompositeObserver) OnWorkflowCompleted ¶
func (c *CompositeObserver) OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
func (*CompositeObserver) OnWorkflowFailed ¶
func (c *CompositeObserver) OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
func (*CompositeObserver) OnWorkflowStart ¶
func (c *CompositeObserver) OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
type ConditionFunc ¶
ConditionFunc decides whether a branch should be taken based on the current input. It must be deterministic.
type Engine ¶
type Engine interface {
// RegisterWorkflow registers a definition by name.
RegisterWorkflow(def WorkflowDefinition) error
// Run starts and runs the workflow to completion (synchronously).
Run(ctx context.Context, name string, input any) (*WorkflowInstance, error)
// GetInstance looks up a workflow instance by ID.
// Returns an error if the instance is not found.
GetInstance(ctx context.Context, id string) (*WorkflowInstance, error)
// ListInstances returns workflow instances matching the given options.
// If options are zero-valued, all instances are returned.
ListInstances(ctx context.Context, opts InstanceListOptions) ([]*WorkflowInstance, error)
// Resume restarts a previously failed workflow instance.
// Semantics (first iteration):
// - Only FAILED instances can be resumed.
// - The instance is replayed from the beginning using its stored Input.
// - The same instance ID is reused; Status/Err/Output/CurrentStep are updated.
Resume(ctx context.Context, id string) (*WorkflowInstance, error)
// Signal delivers a named signal to a waiting workflow instance and
// resumes it from the step that requested the signal.
Signal(ctx context.Context, id string, name string, payload any) (*WorkflowInstance, error)
// RecoverStuckInstances scans for in-flight workflow instances that are
// still marked as StatusRunning (for example after a process crash) and
// marks them as StatusFailed with a standard error message.
//
// It returns the number of instances it updated.
//
// This method is intended to be called on process startup *before*
// starting workers or accepting new work, so that no instance is
// legitimately running when it is executed.
RecoverStuckInstances(ctx context.Context) (int, error)
}
Engine is the high-level engine API (iteration 1: synchronous).
func EngineFromContext ¶
EngineFromContext retrieves the Engine previously attached with WithEngine. It returns nil if no engine is present in ctx.
type InstanceListOptions ¶
type InstanceListOptions struct {
// WorkflowName, if non-empty, limits results to instances of the given workflow.
WorkflowName string
// Status, if non-empty, limits results to instances with the given status.
Status Status
}
InstanceListOptions controls how instances are listed. Zero values mean "no filter" for that field.
type LoggingObserver ¶
LoggingObserver writes structured logs using log/slog.
func (*LoggingObserver) OnStepCompleted ¶
func (o *LoggingObserver) OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, idx int, err error, d time.Duration)
func (*LoggingObserver) OnStepStart ¶
func (o *LoggingObserver) OnStepStart(ctx context.Context, inst *WorkflowInstance, stepName string, idx int)
func (*LoggingObserver) OnWorkflowCompleted ¶
func (o *LoggingObserver) OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
func (*LoggingObserver) OnWorkflowFailed ¶
func (o *LoggingObserver) OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
func (*LoggingObserver) OnWorkflowStart ¶
func (o *LoggingObserver) OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
type NoopObserver ¶
type NoopObserver struct{}
NoopObserver is an Observer that does nothing. It is used as the default when no observer is configured.
func (NoopObserver) OnStepCompleted ¶
func (NoopObserver) OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, idx int, err error, d time.Duration)
func (NoopObserver) OnStepStart ¶
func (NoopObserver) OnStepStart(ctx context.Context, inst *WorkflowInstance, stepName string, idx int)
func (NoopObserver) OnWorkflowCompleted ¶
func (NoopObserver) OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
func (NoopObserver) OnWorkflowFailed ¶
func (NoopObserver) OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
func (NoopObserver) OnWorkflowStart ¶
func (NoopObserver) OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
type Observer ¶
type Observer interface {
// OnWorkflowStart is called once when a workflow instance is first started
// (Run), before the first step is executed.
OnWorkflowStart(ctx context.Context, inst *WorkflowInstance)
// OnWorkflowCompleted is called when a workflow instance successfully
// reaches StatusCompleted.
OnWorkflowCompleted(ctx context.Context, inst *WorkflowInstance)
// OnWorkflowFailed is called when a workflow instance transitions to
// StatusFailed.
OnWorkflowFailed(ctx context.Context, inst *WorkflowInstance, err error)
// OnStepStart is called before invoking a step function.
// stepIndex is the 0-based index into WorkflowDefinition.Steps.
OnStepStart(ctx context.Context, inst *WorkflowInstance, stepName string, stepIndex int)
// OnStepCompleted is called after a step function returns, for both
// successes and failures (err != nil).
OnStepCompleted(ctx context.Context, inst *WorkflowInstance, stepName string, stepIndex int, err error, duration time.Duration)
}
Observer receives callbacks from the workflow engine for logging and metrics.
Implementations should be fast and non-blocking; heavy work should be done asynchronously so as not to delay workflow execution.
func NewCompositeObserver ¶
NewCompositeObserver creates an Observer that forwards events to each non-nil observer in obs.
func NewLoggingObserver ¶
NewLoggingObserver creates an Observer that logs workflow / step lifecycle events using the provided slog.Logger. If logger is nil, slog.Default() is used.
type ParallelResult ¶
ParallelResult represents the out from a parallel step to next step.
type RetryPolicy ¶
type RetryPolicy struct {
MaxAttempts int
// Deprecated: prefer InitialBackoff + BackoffMultiplier. If
// InitialBackoff is zero and BackoffMultiplier is zero, Backoff
// is used as the initial delay between retries.
Backoff time.Duration
// InitialBackoff is the base delay before the first retry.
InitialBackoff time.Duration
// MaxBackoff caps the delay between retries. If zero, there is no cap.
MaxBackoff time.Duration
// BackoffMultiplier is the factor by which the delay grows after each
// failed attempt. If <= 0, a default of 2.0 is used.
//
// Example:
// InitialBackoff = 100ms, BackoffMultiplier = 2.0
// attempt 1 -> 2: sleep 100ms
// attempt 2 -> 3: sleep 200ms
// attempt 3 -> 4: sleep 400ms (capped by MaxBackoff if set)
BackoffMultiplier float64
}
RetryPolicy controls how a step is retried when it returns an error. MaxAttempts includes the first attempt. For example:
MaxAttempts = 1 => no retries (just the initial call) MaxAttempts = 3 => initial call + up to 2 retries
Backoff is the delay between failed attempts. It is not applied before the first attempt. If zero, retries happen immediately.
type SelectorFunc ¶
SelectorFunc picks a branch key from the input. It must be deterministic.
type SignalPayload ¶
SignalPayload is used by the engine to resume a workflow step that previously requested to wait for a signal.
type StepDefinition ¶
type StepDefinition struct {
Name string
Fn StepFunc
Retry *RetryPolicy
}
StepDefinition describes a named step.
type StepFunc ¶
StepFunc is a single step in a workflow. Iteration 1: keep it simple with `any`, we can add generics later.
func IfStep ¶
func IfStep(cond ConditionFunc, thenStep StepFunc, elseStep StepFunc) StepFunc
IfStep returns a step that evaluates cond on the input and, depending on the ParallelResult, runs thenStep or elseStep.
The selected branch is executed as a nested step (i.e. the engine only sees this as a single step); retries/backoff for this step apply to the entire nested execution.
If elseStep is nil, the input is passed through unchanged on the false branch.
func LoopStep ¶
LoopStep returns a StepFunc that executes body a fixed number of times. The loop is treated as a single engine step; retries/backoff (if any) apply to the entire loop execution.
func ParallelMapStep ¶
ParallelMapStep returns a StepFunc that expects the input to be a slice or array and runs fn in parallel for each element.
Input:
- A slice or array Value (e.g. []T).
Behavior:
- For each element input[i], fn(ctx, input[i]) is executed in its own goroutine.
- The outputs are collected into a []any of the same length, preserving the original order.
- If any call returns an error, the first error is returned.
- If ctx is cancelled, ctx.Err() is returned.
This is a convenient fan-out/fan-in helper for data-parallel workloads.
func ParallelStep ¶
ParallelStep returns a StepFunc that runs multiple child steps in parallel and collects their outputs.
Semantics:
- All non-nil child steps receive the same input Value.
- The ParallelResult is a []any whose length equals len(steps), preserving order.
- If any child step returns an error, the *first* error is returned and no further processing is done after all goroutines finish.
- If ctx is cancelled, ctx.Err() is returned.
NOTE: This is an in-process parallelism helper. The underlying engine still sees this as a single step, so retries/backoff apply to the whole parallel group as a unit.
func SleepStep ¶
SleepStep returns a StepFunc that waits for the given duration before passing the input through unchanged.
It is context-aware: if the context is cancelled during the sleep, it returns ctx.Err and the workflow will fail at this step.
func SleepUntilStep ¶
SleepUntilStep returns a StepFunc that waits until the given deadline before passing the input through unchanged.
If the deadline is in the past or equal to now, it returns immediately. It is context-aware: if the context is cancelled while waiting, it returns ctx.Err and the workflow will fail at this step.
func StartChildrenStep ¶
func StartChildrenStep(specsFn func(input any) ([]ChildWorkflowSpec, error)) StepFunc
StartChildrenStep returns a step that starts one or more child workflows and returns their instance IDs as []string.
The specsFn callback is given the current input and must deterministically construct the list of child workflows to start.
func SwitchStep ¶
func SwitchStep(selector SelectorFunc, branches map[string]StepFunc, defaultStep StepFunc) StepFunc
SwitchStep returns a step that selects one of several branches based on selector(input). The branches map holds per-key steps; if no branch matches, defaultStep is used (if non-nil), otherwise the input is passed through unchanged.
As with IfStep, the chosen branch is executed as a nested step from the engine's perspective.
func TypedLoop ¶
TypedLoop returns a StepFunc that executes a strongly-typed body a fixed number of times. The loop is treated as a single engine step.
func TypedStep ¶
TypedStep wraps a strongly-typed function into a generic StepFunc. It performs a type assertion on input at runtime and returns an error if the input is not of the expected type.
func TypedWhile ¶
TypedWhile returns a StepFunc that repeatedly executes a strongly-typed body while cond(input) is true. The loop is treated as a single engine step.
func WaitForAnyChildStep ¶
WaitForAnyChildStep waits until any one of the specified child workflow instances has reached a terminal state.
getIDs extracts the child instance IDs from the input (for example, from the []string returned by StartChildrenStep).
Semantics:
- If getIDs(input) returns an empty slice, the step returns (nil, nil).
- If any child is StatusFailed, the step returns a hard error describing the failure (not a WaitForAnyChildError).
- If any child is StatusCompleted, the step returns that child ID as output. The "first" completed child is determined by the order of IDs returned by getIDs.
- If no child is terminal yet (all are PENDING/RUNNING/etc.), the step returns a *WaitForAnyChildError with the IDs and PollAfter interval. The engine should treat this as a request to park the workflow and resume it later.
func WaitForAnySignalStep ¶
WaitForAnySignalStep returns a step that parks the workflow until a signal with any of the given names is delivered via Engine.Signal.
Behavior:
- At first invocation (normal forward execution), it ignores its input and returns NewWaitForSignalError(names[0]) which causes the engine to mark the instance as WAITING.
- When resumed via Engine.Signal, the engine passes a SignalPayload as input (Name, Data). If Name is in the allowed list, this step returns that SignalPayload as its output and the workflow continues.
- If a signal with an unexpected name is delivered, the step will request to wait again via NewWaitForSignalError(names[0]).
This is useful for branching decisions such as approve/reject flows, where the next step can switch on the SignalPayload.Name to decide behavior.
func WaitForChildrenStep ¶
WaitForChildrenStep returns a step that waits until all specified child workflow instances have completed.
getIDs extracts the child instance IDs from the input (for example, from the []string returned by StartChildrenStep).
Durable semantics:
- Each invocation checks child states exactly once.
- If some children are still running/pending, the step returns a WaitForChildrenError with a suggested PollAfter duration.
- The engine must treat WaitForChildrenError like a "WAITING" signal: mark the instance as WAITING and schedule a resume after PollAfter.
- When the workflow is resumed, this step is re-invoked with the same input, re-checks statuses, and eventually returns the children outputs once all are completed.
func WaitForSignalStep ¶
WaitForSignalStep returns a step that parks the workflow until a signal with the given name is delivered via Engine.Signal.
Semantics:
- First time the step runs, it ignores its input and returns NewWaitForSignalError(name). The engine marks the instance as WAITING and stops execution.
- When Engine.Signal is called, the engine resumes this step with input set to SignalPayload{Name: name, Data: payload}. In that case, the step returns payload (Data) as its output and the workflow continues with the next step.
func WhileStep ¶
func WhileStep(cond ConditionFunc, body StepFunc) StepFunc
WhileStep returns a StepFunc that repeatedly executes body while cond(input) is true. The entire loop is treated as a single engine step: retries/backoff (if any) apply to the whole loop execution.
type TimeoutPayload ¶
type TimeoutPayload struct {
Reason string
}
TimeoutPayload is a special payload used for auto-expiry signals. Workflows can check for this type to detect that a wait timed out.
type WaitForAnyChildError ¶
WaitForAnyChildError signals that the workflow should pause until one of the given child workflows has completed.
func (*WaitForAnyChildError) Error ¶
func (e *WaitForAnyChildError) Error() string
type WaitForChildrenError ¶
WaitForChildrenError is a sentinel error used by WaitForChildrenStep to tell the engine that the parent workflow should be parked (WAITING) and resumed later to re-check the child statuses.
The engine is responsible for scheduling a resume after PollAfter.
func (*WaitForChildrenError) Error ¶
func (e *WaitForChildrenError) Error() string
type WorkflowDefinition ¶
type WorkflowDefinition struct {
Name string
Steps []StepDefinition
}
WorkflowDefinition describes a workflow as a sequence of steps.
Example ¶
ExampleWorkflowDefinition shows how to build a workflow definition directly using the api package and register it on an Engine.
package main
import (
"context"
"fmt"
"log"
"github.com/petrijr/fluxo"
"github.com/petrijr/fluxo/pkg/api"
)
func main() {
ctx := context.Background()
// Build a simple definition manually.
def := api.WorkflowDefinition{
Name: "AddPrefix",
Steps: []api.StepDefinition{
{
Name: "addPrefix",
Fn: func(ctx context.Context, input any) (any, error) {
s, ok := input.(string)
if !ok {
return nil, fmt.Errorf("expected string input, got %T", input)
}
return "prefix:" + s, nil
},
},
},
}
// Use a real engine implementation from the fluxo package.
eng := fluxo.NewInMemoryEngine()
if err := eng.RegisterWorkflow(def); err != nil {
log.Fatal(err)
}
inst, err := eng.Run(ctx, def.Name, "value")
if err != nil {
log.Fatal(err)
}
fmt.Printf("instance %s finished with status %s and output %v\n",
inst.ID, inst.Status, inst.Output)
}
Output:
type WorkflowInstance ¶
type WorkflowInstance struct {
ID string
Name string
Status Status
Output any
Err error
// Input is the original input provided to Run when this instance
// was first started. It is used for deterministic replay on resume.
Input any
// CurrentStep tracks progress through the workflow steps.
// Semantics:
// - Before any steps run: 0 (default)
// - While running step i: i
// - After successful completion: len(steps)
// - On failure: Index of the step that failed (or was cancelled).
CurrentStep int
// StepResults holds the output of successfully completed steps,
// keyed by their index in the WorkflowDefinition.Steps slice.
//
// This is used for step-level idempotency: on replay/resume, the engine
// can skip re-running steps that have already succeeded and reuse their
// cached outputs as inputs to downstream steps.
StepResults map[int]any
}
WorkflowInstance holds the ParallelResult of a run.
func InstanceFromContext ¶
func InstanceFromContext(ctx context.Context) *WorkflowInstance