Skip to main content

1. Workflows as Directed Acyclic Graphs (AST)

In Siglo, a workflow is not a simple promise chain. It is an executable Abstract Syntax Tree (AST) composed of typed nodes:
  • StepNode: An isolated unit of work with input schemas, lifecycles, retries, and policies.
  • SequenceNode: Sequential execution pipeline created with flow(...).
  • ParallelNode: Concurrent fan-out/fan-in with merge strategies (parallel, race).
  • BranchNode: Dynamic conditional routing and predicate dispatch (branch, when).
  • WaitNode: Durable event suspension or timer sleep (waitForEvent, wait).
  • MapNode: Concurrently bounded array transformations (map).
Because workflows are represented as ASTs, they can be statically inspected, validated for cycles, visualised as diagrams, and checked before runtime execution.

2. Context & Accumulated Inference

When steps execute sequentially, return values are merged into an Accumulated Context. Each subsequent step receives the combined outputs of all prior steps. TypeScript automatically computes the union type of this accumulated state at compile time:
If a step needs to access the exact isolated output of an earlier step without risk of key collisions, it can read from param.$steps.<stepName> (or param.$history.<stepName>).

3. Step Lifecycle Pipeline

Each step goes through a strict 5-phase lifecycle:
  1. Validation: Evaluates field rules (step.spec(...)) or Standard Schemas (step.schema(...)). Rejections throw ValidationException.
  2. Before Hook (onBefore): Runs predicates to decide whether to execute the action or skip it. If skipped, onSkip provides fallback data.
  3. Action: Executes the primary asynchronous business logic. If idempotency (step.idempotent(...)) or caching (step.cache(...)) is configured, cached results short-circuit execution.
  4. After Hook (onAfter): Transforms or augments the action output before it is merged into accumulated context.
  5. OnFail Hook (onFail): Evaluates retry predicates, calculates backoff delay (fixed, linear, exponential with jitter), and coordinates compensation triggers if retries are exhausted.

4. Reserved Keys and Namespaces

Siglo reserves specific context keys prefixed with $ to expose execution metadata without polluting business properties:

Minimal Example


Failure Example: Phase Diagnostic Tagging

When an action or lifecycle hook throws, the runtime wraps the failure into a SigloError subclass and tags it with diagnostic metadata:

Testing Example


Operational Caveats

  1. Avoid Overwriting Context Keys: While later steps can overwrite earlier keys if intended, naming step outputs distinctly (e.g. user, order, payment) maintains clean history and avoids confusion. If needed, access raw outputs via $steps.<stepName>.
  2. Never Mutate Param Directly: Treat input parameters as read-only. Always return a new object with changes.
  3. Namespace Isolation: In multi-tenant environments, pass { namespace: tenantId } in execution options to isolate caches and checkpoints.
  4. Native Abort Signals: When passing signals to external libraries (such as fetch(url, { signal: param.signal })), prefer param.signal over legacy accessors.