-
Notifications
You must be signed in to change notification settings - Fork 4
Race condition for side effects #128
Comments
Is it possible to provide some sample project to better understand what is your problem and how have you defined state machine? |
Because I've worked around the problem, I can't invest a lot of time in creating a sample project. I wrote the feedback above in case there is in an opportunity to improve CoRedux for others who have a similar use case. If I do find the time to publish a sample project, I will post a link to it. |
@Tapchicoma I am still seeing this race condition so I'm providing https://github.com/mosofsky/CoReduxSideEffectRaceCondition as a sample project to help you better understand the problem. I eagerly await your feedback. |
I seem to have found a solution by implementing
I published the solution as an update to the sample project (https://github.com/mosofsky/CoReduxSideEffectRaceCondition) |
Thank you for repro project - I will check how you've solved this race-condition 👍 |
I think the reason you had this was:
|
Thank you @Tapchicoma . I thought the problem was because
|
Yeah, idea behind |
Thanks again for all your help @Tapchicoma . CoRedux is working really well for my project now that I've overcome the challenge of handling asynchronous UI events. CoRedux has scaled to 91 actions and 80 state variables. Great work guys! To demonstrate how I've managed to handle asynchronous UI code, I created another sample project at https://github.com/mosofsky/how-to-coredux . This second sample project builds on the first by showing how CoRedux side effects can facilitate asynchronous UI testing via Espresso's idling resource counter. |
My understanding was that side effects were supposed to be evaluated after each reduction but what I'm seeing are race conditions instead.
Basically what I'm trying to do is automatically show a window ("Window1") after another window ("Window2") is hidden.
Background
Window1 should not always be shown after Window2 is closed. It depends on whether Window1 was originally open before the user tapped a button on Window1 that opened Window2.
User Scenario A:
User Scenario B:
I have the following actions:
ShowWindow1
HideWindow1
ShowWindow2 (parameter: returnToWindow1: true/false)
HideWindow2
When the user taps the button on Window1, it dispatches ShowWindow2 with returnToWindow1=true. When the user taps a button on the main screen to open Window2, it dispatches ShowWindow2 with returnToWindow1=false.
Moreover, I have a "render" function which observes changes to the state. Render takes care of opening and closing windows. To record that it's done rendering, it dispatches these actions:
Window1Shown
Window1Hidden
Window2Shown
Window2Hidden
Render and reduce work together with booleans. For example when HideWindow2 gets reduced, it changes a boolean in the state, isWindow2Hiding, to true. The render function looks for isWindow2Hiding and if it's true, it closes Window2. Then it dispatches Window2Hidden which sets isWindow2Hiding to false.
Problem
After my reducer handles HideWindow2, I expect my side effect to see state changed by HideWindow2. But instead the side effect sees the state changed not only by HideWindow2 but also Window2Hidden!
One correct behavior is the side effect is called twice (once for HideWindow2 and once for Window2Hidden). HOWEVER, the state the side effect sees is that of Window2Hidden. Consequently, the variable returnToWindow1 has already been changed from true to false so the the side effect doesn't know it should dispatch ShowWindow1.
Workaround
Since this is a race condition problem, I found I could work around it by introducing a delay in my render function. When render sees that isWindow2Hiding==true, it closes the window and waits 10 milliseconds before dispatching Window2Hidden. This is just enough time for the right order of operations:
Why doesn't the side effect get called after the first action is reduced? Why does it reduce two actions before evaluating the side effect?
The text was updated successfully, but these errors were encountered: