6. Execution Lifecycle#
Every node in an execution instance is in exactly one state. The state machine is normative: two conforming runtimes must agree on which state a node reached, and that agreement is what makes execution traces comparable across implementations.
6.1 The states#
| state | meaning | terminal |
|---|---|---|
PENDING | created; join condition not yet satisfied | no |
READY | join condition satisfied; may be scheduled | no |
RUNNING | executing | no |
RETRYING | an attempt failed; retries remain; waiting out the backoff | no |
SUCCEEDED | completed successfully | yes |
SKIPPED | reached, and its guard evaluated false — a successful outcome | yes |
FAILED | failed with retries exhausted | yes |
CANCELLED | terminated before completion | yes |
COMPENSATED | had succeeded, then was rolled back | yes |
6.2 Legal transitions#
A conforming runtime MUST NOT perform any transition not listed here.
| from | to | when |
|---|---|---|
PENDING | READY | join condition satisfied |
PENDING | CANCELLED | instance cancelled while the node was still waiting |
READY | RUNNING | scheduled, guard true |
READY | SKIPPED | guard evaluated false |
READY | CANCELLED | instance cancelled, or a sibling satisfied an any join |
RUNNING | SUCCEEDED | execution completed |
RUNNING | FAILED | execution failed with no retries remaining |
RUNNING | RETRYING | execution failed with retries remaining |
RUNNING | CANCELLED | cancelled — only if idempotent="true" |
RETRYING | READY | backoff elapsed |
RETRYING | FAILED | retry budget exhausted, or a non-retryable error class |
RETRYING | CANCELLED | instance cancelled |
SUCCEEDED | COMPENSATED | compensation ran during unwinding |
Everything else is a runtime defect.
6.2.1 Cancelling a RUNNING node#
A runtime MUST NOT cancel a RUNNING node declared idempotent="false". It MUST let the attempt finish and then discard the result.
Interrupting a non-idempotent action mid-flight leaves the world in a state nobody can describe: was the payment sent? did the arm complete the grasp? A result that is discarded is at least a known outcome.
6.3 SKIPPED is a success#
The state most often implemented wrongly.
SKIPPED is terminal and successful. A node whose guard evaluated false did exactly what the document asked. So:
- outgoing
controledges are satisfied; - outgoing
dataedges are satisfied for scheduling, but the values areunavailable (see §5.6);
- outgoing
erroredges are not taken — nothing failed.
Treating skip as failure means any optional step halts everything after it, which is not what a guard means.
6.4 PENDING at completion is normal#
A node that was never reached stays PENDING when the instance completes.
This is the expected outcome for the branch a decision did not take. It is not an error, and a runtime MUST NOT report the instance as failed because nodes remain PENDING.
Distinguish it from the two states it is most often confused with. All three are ordinary outcomes, and an incident review needs to tell them apart:
| state | means | successors |
|---|---|---|
PENDING at completion | never reached — no path arrived | also not reached |
SKIPPED | reached, and its guard was false | control successors still run |
CANCELLED | reached and started, then stopped | not reached |
Conflating PENDING with SKIPPED makes the untaken branch of every decision report as a success that ran.
6.5 Loop iterations#
A loop node has its own lifecycle, and so does each iteration of its body. Iteration states are scoped to the iteration and do not overwrite one another — iteration 3 failing does not put the body node in FAILED for iterations 4 onward.
The loop node's own outcome follows onItemFailure:
onItemFailure | loop node reaches |
|---|---|
fail (default) | FAILED on the first iteration failure |
continue | SUCCEEDED if any iteration succeeded; FAILED if all failed |
break | SUCCEEDED, stopping at the first failure |
6.6 Traces#
A runtime SHOULD emit a trace of state transitions. A trace entry SHOULD carry the node id, both states, a timestamp, the attempt number, and for FAILED, the error class and message.
Conformance at Executing and Full level compares the normalised sequence of transitions, not timing and not the interleaving of independent branches — two runtimes may schedule unrelated work in different orders. What they may not do is disagree about whether a node ran, was skipped, retried, failed or was compensated. See conformance.