I have multiple WarmUp actions dispatched one after another here
The 2nd action is expected to perform based on the state changes by the 1st action, in this case, the 2nd WarmUp action should not go inside this block because the appState.needsWarmup is already updated to false by the 1st action
Everything works fine when I directly use the Store.dispatch, but things work weirdly after I tried to create my custom serial dispatch queue for actions.
Console logs
Warmup-ing ...
doneWarmup
Done warmup ...
warmup
warmup
Console logs
Warmup-ing ...
warmup
Warmup-ing ...
warmup
Warmup-ing ...
doneWarmup
Done warmup ...
doneWarmup
Done warmup ...
doneWarmup
Done warmup ...
I've put the expectations also here in the code comment
https://github.com/MichaelGuoXY/ReSwiftExample/blob/master/ReSwiftExample/ReSwift/ReSwift.swift#L85-L111
I'm not sure if it's the right way that I tried, please do advice on how to use a custom serial queue for actions & state changes
https://github.com/MichaelGuoXY/ReSwiftExample
Please download and try, no pod install required
It's easy to understand with Main thread, the 2nd action will be dispatched after the 1st action being dispatched and states being updated. But how can I achieve the same thing with a custom serial queue?
Why do you need to dispatch three actions in a row instead of just one?
Why do you need to dispatch three actions in a row instead of just one?
There are cases the same action can be dispatched at almost the same time from different places. No need to be like what's in the example, this is just to reproduce the issue more easily.
I'm not sure if I understand the problem, but in the middleware, you're dispatching an action before having finished processing the previous one (you're calling next(action) at the end). You can call next whenever you want, and then dispatch more actions in your middleware, but the order is important. Does that help?
The issue you're experiencing is being caused by your use of mainStore.dispatch inside of middleware.
Middleware has its own dispatch function available (as seen in the closure parameters) that you should be using instead, and indeed fixes the problem.
Change mainStore.dispatch(AppAction.doneWarmup) to dispatch(AppAction.doneWarmup)
By dispatching again on mainStore you were adding the doneWarmup to the END of your queue, which was already stacked with 3x warmup actions, and because it was processing those first, it was also dispatching 3x doneWarmup.
In fact, you don't have any invalid concurrency issues occurring, which is why the fatal error is not happening. Your code is perfectly safe, just invalid logically for what you want.
using the provided dispatch allows the doneWarmup to happen immediately during the processing of the first warmup, and fixes the bug.
The issue you're experiencing is being caused by your use of
mainStore.dispatchinside of middleware.
Middleware has its owndispatchfunction available (as seen in the closure parameters) that you should be using instead, and indeed fixes the problem.Change
mainStore.dispatch(AppAction.doneWarmup)todispatch(AppAction.doneWarmup)By dispatching again on mainStore you were adding the
doneWarmupto the _END_ of your queue, which was already stacked with 3xwarmupactions, and because it was processing those first, it was also dispatching 3xdoneWarmup.In fact, you don't have any invalid concurrency issues occurring, which is why the fatal error is not happening. Your code is perfectly safe, just invalid logically for what you want.
using the provided
dispatchallows thedoneWarmupto happen immediately during the processing of the firstwarmup, and fixes the bug.
Thanks, got it now.
So I guess it depends on the business logic whether to use dispatch or mainStore.dispatch, in other words, whether to immediately dispatch the action or append the action to the END of the dispatch queue. Please correct me if I am wrong.
Correct, @MichaelGuoXY. It is important one considers when the action will be processed when dispatching.
Most helpful comment
The issue you're experiencing is being caused by your use of
mainStore.dispatchinside of middleware.Middleware has its own
dispatchfunction available (as seen in the closure parameters) that you should be using instead, and indeed fixes the problem.https://github.com/MichaelGuoXY/ReSwiftExample/blob/bdad901e2018ab87f4c6cb4683042e81e6f217f3/ReSwiftExample/ReSwift/ReSwift.swift#L46
Change
mainStore.dispatch(AppAction.doneWarmup)todispatch(AppAction.doneWarmup)By dispatching again on mainStore you were adding the
doneWarmupto the END of your queue, which was already stacked with 3xwarmupactions, and because it was processing those first, it was also dispatching 3xdoneWarmup.In fact, you don't have any invalid concurrency issues occurring, which is why the fatal error is not happening. Your code is perfectly safe, just invalid logically for what you want.
using the provided
dispatchallows thedoneWarmupto happen immediately during the processing of the firstwarmup, and fixes the bug.