Static For-Loop Node

A deterministic iteration node for bounded loops. Emits per-iteration output, supports pause/continue/stop control signals, and persists state for crash-safe resume behavior.

Spec v1.1 Sequential by default IoT-aware ack model Dynamic loop — TODO

Execution Overview

All loop nodes share a common execution model: they suspend between iterations using the bookmark pattern, persisting their current iteration state into the workflow instance. This means a process restart mid-loop resumes at the last completed iteration — not from the beginning.

Each iteration fires an onIteration output port carrying typed data. The loop either continues immediately (fire-and-forget) or waits for an acknowledgement signal from downstream nodes before advancing (ack mode).

Port Overview

Input ports
start
pause
continue
stop
StaticForLoopNode
Loop
Output ports
onIteration
onComplete
onStop
onIterationTimeout
onError

Node Properties

Design-time properties that control range behavior, acknowledgement mode, failure handling, and runtime concurrency guarantees.

StaticForLoopNode
Spec v1.1 Sequential
Iterates over a fixed numeric range defined at workflow design time. Range is set in the WorkflowDefinition and cannot be changed at runtime. On each iteration, the current value is emitted via the onIteration output port. Supports external pause, continue, and stop control via input signal ports.

Input Properties

Property Type Default Description
from int required Starting value of the loop (inclusive).
e.g. from=0 starts the first iteration with value=0
to int required Ending value of the loop (exclusive — like Python range()).
e.g. from=0, to=5 yields values 0,1,2,3,4
step int 1 Increment applied after each iteration. Use a negative value with from > to for countdown loops.
e.g. from=10, to=0, step=-2 yields 10,8,6,4,2
iterationMode enum Sequential Sequential — next iteration starts only after current completes (or is acked).
Concurrent — all iterations fan-out as independent pointers simultaneously.
Concurrent mode requires maxConcurrency to avoid flooding downstream systems.
iterationDelayMs int 0 Milliseconds to wait after an iteration completes before starting the next.
Only applies in Sequential mode.
ack bool false false — fire and forget. Loop advances immediately after onIteration.
true — loop suspends and waits for a signal to the continue input port before advancing.
ackTimeoutMs int 0 Milliseconds to wait for acknowledgement before timing out. 0 = wait indefinitely.
Only relevant when ack: true. Timeout fires the onIterationTimeout port.
ackMode enum Any Any — resume when any one connected downstream node sends ack.
All — resume only when all connected downstream nodes have acked.
Only relevant when ack: true.
maxConcurrency int Maximum concurrent iterations when iterationMode: Concurrent.
Strongly recommended for IoT command sequences. Has no effect in Sequential mode.
onIterationError enum Halt Halt — stop the loop and fire onError.
Continue — skip the failed iteration and advance.
Retry(n) — retry the current iteration up to n times before applying Halt or Continue.
Range validation at publish time The engine validates that the range produces at least one iteration when the definition is published. A definition with from=5, to=3, step=1 (impossible range) is rejected before any instance can be created.

Port Detail

Input ports
start control
Begins the loop from from. Ignored if the loop is already running.
pause control
Suspends iteration after the current iteration completes. Instance status remains Running.
continue control
Resumes a paused loop, OR serves as the ack signal when ack: true. Dual purpose — context determines behaviour.
stop control
Terminates the loop immediately. Does not wait for pending acks. Fires the onStop output port.
Output ports
onIteration signal
Fires on each iteration. Carries current iteration data.
{ index: int,
  value: int,
  isFirst: bool,
  isLast: bool }
onComplete signal
Fires when all iterations finish naturally (not stopped or errored).
{ totalIterations: int, completedAt: timestamp }
onStop signal
Fires when stopped externally via the stop input port.
{ stoppedAtValue: int, iterationsCompleted: int }
onIterationTimeout error
Fires per iteration when ackTimeoutMs is exceeded. Only when ack: true and ackTimeoutMs > 0.
{ value: int, index: int }
onError error
Fires when onIterationError: Halt and an iteration fails.
{ value: int, index: int, error: string }

Input port priority

When multiple control signals arrive simultaneously at the same iteration boundary:

1 stop — highest priority, always terminates the loop immediately
2 pause — suspends after current iteration; overrides continue
3 continue — lowest priority, resumes only if not paused or stopped

Concurrency model

One loop node runs per workflow instance. Two instances of the same definition have completely independent loop state and iteration counters.

Sequential mode
One active iteration at a time. Loop pointer suspends between iterations. Resumes from the last completed iteration after a process restart.
i=0 ··· i=1 ··· i=2 one at a time
Concurrent mode
All iterations fan-out as independent execution pointers. A FanInGate downstream collects results. Cap with maxConcurrency to avoid flooding.
i=0 i=1 i=2 i=3 all at once
IoT warning — Concurrent mode Without maxConcurrency, a loop with from=0, to=1000 in Concurrent mode dispatches 1000 simultaneous device commands. Always set maxConcurrency when targeting physical devices.

Persisted state (crash recovery)

Written to WorkflowInstance.State.NodeOutputs[nodeId] on every iteration suspension:

currentValueint
Value at last suspension. Loop resumes from here on restart.
iterationsCompletedint
Count of successfully completed iterations so far.
isPausedbool
True if the loop was externally paused via the pause input port.
pendingAcksint
Number of acks still expected. Only set when ackMode: All.
statusenum
Running | Paused | Completed | Stopped | Failed
lastIterationAttimestamp
Timestamp of last completed iteration. Used for delay calculation.

Planned Node Types

The following loop node variants are planned for future releases. Design notes are preliminary.

Design note — ack model applies to all loop types The ack / ackTimeoutMs / ackMode properties and the pause/continue/stop input port pattern are intended to be consistent across all loop node variants.