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#

Node lifecycle state machine A node starts PENDING. When its join condition is satisfied it becomes READY, then RUNNING. From RUNNING it reaches SUCCEEDED, or FAILED. A failure with retries remaining goes to RETRYING and back to READY. A node whose guard evaluates false goes from READY to SKIPPED. A node cancelled before it finished goes to CANCELLED; a node no path ever reached simply stays PENDING. SUCCEEDED, SKIPPED, FAILED, CANCELLED and COMPENSATED are terminal. PENDING

<rect x="164" y="110" width="90" height="40" rx="20" fill="none" stroke="currentColor" stroke-width="1.5" opacity=".8"/> <text x="209" y="135">READY</text>

<rect x="324" y="110" width="100" height="40" rx="20" fill="none" stroke="currentColor" stroke-width="2"/> <text x="374" y="135">RUNNING</text>

<rect x="484" y="110" width="110" height="40" rx="20" fill="currentColor" opacity=".13"/> <rect x="484" y="110" width="110" height="40" rx="20" fill="none" stroke="currentColor" stroke-width="1.5"/> <text x="539" y="135">SUCCEEDED</text>

<rect x="484" y="192" width="110" height="40" rx="20" fill="currentColor" opacity=".13"/> <rect x="484" y="192" width="110" height="40" rx="20" fill="none" stroke="currentColor" stroke-width="1.5"/> <text x="539" y="217">FAILED</text>

<rect x="300" y="230" width="100" height="40" rx="20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-dasharray="4 3" opacity=".8"/> <text x="350" y="255">RETRYING</text>

<rect x="150" y="230" width="100" height="40" rx="20" fill="currentColor" opacity=".13"/> <rect x="150" y="230" width="100" height="40" rx="20" fill="none" stroke="currentColor" stroke-width="1.5"/> <text x="200" y="255">SKIPPED</text>

<rect x="640" y="110" width="115" height="40" rx="20" fill="currentColor" opacity=".13"/> <rect x="640" y="110" width="115" height="40" rx="20" fill="none" stroke="currentColor" stroke-width="1.5"/> <text x="697" y="135">CANCELLED</text>

<rect x="640" y="192" width="130" height="40" rx="20" fill="currentColor" opacity=".13"/> <rect x="640" y="192" width="130" height="40" rx="20" fill="none" stroke="currentColor" stroke-width="1.5"/> <text x="705" y="217">COMPENSATED</text>

<text x="440" y="30" font-size="11.5" opacity=".65">shaded = terminal</text> </g> </svg> </div>

statemeaningterminal
PENDINGcreated; join condition not yet satisfiedno
READYjoin condition satisfied; may be scheduledno
RUNNINGexecutingno
RETRYINGan attempt failed; retries remain; waiting out the backoffno
SUCCEEDEDcompleted successfullyyes
SKIPPEDreached, and its guard evaluated false — a successful outcomeyes
FAILEDfailed with retries exhaustedyes
CANCELLEDterminated before completionyes
COMPENSATEDhad succeeded, then was rolled backyes

A conforming runtime MUST NOT perform any transition not listed here.

fromtowhen
PENDINGREADYjoin condition satisfied
PENDINGCANCELLEDinstance cancelled while the node was still waiting
READYRUNNINGscheduled, guard true
READYSKIPPEDguard evaluated false
READYCANCELLEDinstance cancelled, or a sibling satisfied an any join
RUNNINGSUCCEEDEDexecution completed
RUNNINGFAILEDexecution failed with no retries remaining
RUNNINGRETRYINGexecution failed with retries remaining
RUNNINGCANCELLEDcancelled — only if idempotent="true"
RETRYINGREADYbackoff elapsed
RETRYINGFAILEDretry budget exhausted, or a non-retryable error class
RETRYINGCANCELLEDinstance cancelled
SUCCEEDEDCOMPENSATEDcompensation 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 control edges are satisfied;
  • outgoing data edges are satisfied for scheduling, but the values are

    unavailable (see §5.6);

  • outgoing error edges 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:

statemeanssuccessors
PENDING at completionnever reached — no path arrivedalso not reached
SKIPPEDreached, and its guard was falsecontrol successors still run
CANCELLEDreached and started, then stoppednot 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:

onItemFailureloop node reaches
fail (default)FAILED on the first iteration failure
continueSUCCEEDED if any iteration succeeded; FAILED if all failed
breakSUCCEEDED, 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.