ExecutionPolicy¶
Have you ever wondered what would happen if you execute an Action very fast, one after another?
For example:
spec {
inState<FooState> {
on<BarAction> { action ->
delay(5000) // wait for 5 seconds
override { OtherState() }
}
}
}
The example above shows a problem with asynchronous state machines like FlowRedux:
If our state machine is in FooState and a BarAction gets triggered, we wait for 5 seconds and then set the state to another state.
What if, while waiting 5 seconds (let’s say after 3 seconds of waiting), another BarAction gets triggered?
That is possible, right?
With ExecutionPolicy you can specify what should happen in that case.
There are three options to choose from:
CancelPrevious: This is the default automatically applied unless specified otherwise. It cancels any previous execution and just runs the latest one. In the example mentioned, it means the previously still-runningBarActionhandler gets canceled and a new one with the latestBarActionstarts.-
Unordered: Choosing this causes all the blocks to continue running but there are no guarantees in which order. For example:spec { inState<FooState> { on<BarAction>(executionPolicy = ExecutionPolicy.Unordered) { delay(randomInt()) // wait for some random time override { OtherState } } } }Let’s assume that we trigger
BarActiontwo times. We use a random amount of seconds for waiting. Since we useUnorderedas the policy foron<BarAction>, the handler block gets executed twice without canceling the previous one (that is the difference toCancelPrevious). Moreover,Unordereddoesn’t make any promise on the order of execution of the block (seeOrderedif you need guarantees on order). Ifon<BarAction>gets executed two times, it will run in parallel and the second execution could complete before the first execution (because of the random waiting time). -
Ordered: In contrast toUnorderedandCancelPrevious,Orderedwill not runon<BarAction>in parallel and will not cancel any previous execution. Instead,Orderedwill preserve the order. Throttled(duration: Duration): This policy will throttle the execution of the block to the specified duration. This means that if the action is triggered more than once within the specified duration, only the first one will be executed.
on<Action> and collectWhileInState() as well as their effect counterparts can specify an ExecutionPolicy:
on<Action>(executionPolicy = ExecutionPolicy.CancelPrevious) { ... }onActionEffect<Action>(executionPolicy = ExecutionPolicy.CancelPrevious) { ... }collectWhileInState(executionPolicy = ExecutionPolicy.CancelPrevious) { ... }collectWhileInStateEffect(executionPolicy = ExecutionPolicy.CancelPrevious) { ... }
Please note that onEnter doesn’t have the option to specify ExecutionPolicy.