Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Workflows

A workflow orchestrates a process as a graph of steps. Authors model it in RuleFlow’s own step vocabulary; RuleFlow compiles it to an AWS Step Functions state machine at deploy time. Step Functions (Standard, not Express) is an implementation detail — you never author or read ASL directly, though POST /engine/compile-workflow will show it to you if you want to look.

Shape

Workflow
├── start
├── steps
│   ├── service_task
│   ├── human_task
│   ├── decision_task
│   ├── wait
│   ├── gateway
│   └── end
├── events
├── timers
└── error_handlers

Step types

  • decision_task — calls a named decision from the same project/release. Executes as an in-process call into a Rust Lambda that links the decision engine directly (no network hop, deterministic, scales to zero) — the same engine entry point /v1/simulate uses, so browser/server/runtime stay in parity. The whole workflow state is passed as input; the engine simply ignores fields outside the decision’s declared inputs, which is what lets a downstream decision read an upstream one’s result.
  • service_task — calls out to an external system through a connector, resolved by a logical action name bound per-tenant to a connector type + config. Executes via a queued task-token callback: the compiled step sends a message to a work queue and waits; a connector worker performs the call and reports success/failure back.
  • human_task — pauses the execution on a task-token callback until a person completes it via the API. Given no timeout by default (human steps are long-lived) — a token lives up to the Step Functions maximum (one year) before it expires.
  • gateway — branches on a prior step’s output (variable/op/value against a $.decisions.…/$.tasks.… path), with a default branch.
  • wait — a timer delay.
  • end — a terminal state; a workflow can declare several.

retry/catch on a step follow Step Functions’ Retry/Catch shape directly (errors, max_attempts/interval_seconds/backoff_rate for retry; errors/next for catch) — authored, passed through by the compiler verbatim.

Reserved state namespaces

The runtime has exactly one shared mutable object per execution: the state that flows step to step. Let input be what was passed to POST .../executions. The invariant:

state = input ⊎ { "decisions": { <stepId>: <outputs> } } ⊎ { "tasks": { <stepId>: <result> } }
  • $.decisions.<stepId> — the outputs object of each decision_task.
  • $.tasks.<stepId> — the result of each service_task/human_task.
  • Everything else under $ is the caller’s original input, never mutated.

decisions and tasks are therefore reserved top-level keys — don’t declare a schema field with either name; a decision/workflow whose input shape uses one would get silently overwritten by the next step’s result.

Results accumulate, they never replace: after a decision_task named score runs, state gains a decisions.score key alongside everything that was already there. A gateway or a later decision_task reads any prior step’s result from that namespace.

Compiling and running

Authoring and compiling are pure and read-only — POST /engine/compile-workflow never touches anything running. A workflow only becomes a runnable machine at deploy time, when the control plane resolves placeholders (engine ARN, inlined decision models, connector queues, default timeouts) against the concrete release being deployed. See Releases, environments & rollback for the deploy lifecycle and Executions for starting and observing runs.

Failure model

Three error classes, deliberately handled differently:

  1. Deterministic decision errors (bad input shape, an expression that can’t evaluate) are reproducible — the same (model, input) fails identically every time. These fail fast; retrying is wasted effort. An author-declared catch on the step is the way to handle them.
  2. Transient AWS faults (throttling, a cold-start hiccup) are not reproducible and should be retried with backoff — declare a retry on the step for this class.
  3. Deploy-time errors (an unresolved decision name, malformed compiled ASL) fail the deploy, never a run — the earliest point they can be caught, and the reason decision models are inlined rather than fetched at runtime.