Deferred Input
Sometimes an input arrives when the FSM isn’t ready to handle it. Rather than dropping it or making the caller retry, call defer() inside a handler to queue the input for automatic replay after a future transition. The caller gets a clean return, and the FSM replays the input once it is in the right state.
Targeted defer
Section titled “Targeted defer”Pass { until: "stateName" } to specify which state should replay the input. The input stays queued until the FSM enters that state, then replays automatically, regardless of how many intermediate transitions occur in between.
The deferred input stays queued through any number of intermediate transitions and replays only when the FSM enters the target state.
Untargeted defer
Section titled “Untargeted defer”Call defer() with no arguments to replay the input on the next transition to any state. This is useful in error or recovery states where you don’t know the destination ahead of time.
When the FSM is in error, any unrecognized input hits the "*" catch-all and gets queued. When retry fires and the FSM transitions to idle, all queued inputs replay there.
Replay mechanics
Section titled “Replay mechanics”The rules below apply when you rely on replay in production code:
- FIFO order. Deferred inputs replay in the order they were queued.
- Replay happens after
_onEntercompletes on the target state. The state is fully initialized before any queued input replays. - Re-deferring is allowed. If a replayed input calls
defer()again, it returns to the queue and waits for the next appropriate state, and the replay cannot loop in place. - Cascading transitions. If a replayed input triggers a transition, the remaining deferred inputs pause and wait for the next appropriate state entry before continuing to replay.
With BehavioralFsm
Section titled “With BehavioralFsm”Deferred inputs are tracked per client. Calling defer() inside a BehavioralFsm handler queues the input for that client, and other clients are unaffected.
Defer in the examples
Section titled “Defer in the examples”- Shopping Cart: targeted defer across multiple transitions (
recordPurchaseAnalyticsqueued frombrowsingthroughvalidatingandapplyingDiscountall the way tocheckout), plus untargeted defer in theerrorstate’s"*"catch-all. - Traffic Intersection: a pedestrian button press deferred from
greentointerruptibleGreen. A press too early in the green phase queues and automatically shortens the interruptible portion when that window opens.