-
Notifications
You must be signed in to change notification settings - Fork 135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid race conditions by collecting on main thread #12912
Avoid race conditions by collecting on main thread #12912
Conversation
📲 You can test the changes from this Pull Request in WooCommerce-Wear Android by scanning the QR code below to install the corresponding build.
|
📲 You can test the changes from this Pull Request in WooCommerce Android by scanning the QR code below to install the corresponding build.
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## release/21.2 #12912 +/- ##
===============================================
Coverage 39.73% 39.73%
Complexity 5983 5983
===============================================
Files 1267 1267
Lines 73227 73228 +1
Branches 10042 10042
===============================================
+ Hits 29094 29096 +2
+ Misses 41567 41566 -1
Partials 2566 2566 ☔ View full report in Codecov by Sentry. 🚨 Try these New Features:
|
...er/src/main/java/com/woocommerce/android/cardreader/internal/connection/ConnectionManager.kt
Show resolved
Hide resolved
@malinajirka I still can reproduce this issue. Rarely but it still there. Here are the logs
Logs.patch My understanding is that as navigation itself is async, there are still cases when updated Not sure what will be a good solution here; Maybe to unsubscribe from |
Nice catch! The asynchronous aspect of the navigation component keeps biting us 😢.
Hmm, this won't help I believe. We change the status to Unknown within the CardReaderModule not the VM. I'll keep thinking about a proper solution. In the meantime, perhaps, we could merge this PR + dismiss the dialog if the only state is Unknown - to avoid this broken looking behavior => and add tracking to learn about how common the scenario is. Wdyt @samiuelson @kidinov ? An ugly workaround could be to keep the last two states in memory - if the last one is unknown, check the one before that. Having said that, I don't like that. |
My understanding is that it doesn't matter that we change it unless we change it before the
If you believe that finding a proper solution now requires more effort than adding tracking and then analyzing the results, then it makes sense. |
That is correct, but unsubscribing from
Considering, the swUpdate flow is triggered automatically by Stripe as part of the Connection flow, I can think of only two proper solutions:
The first one is quite time consuming and the second one feels like an ugly workaround. So I went with the option of dismissing the dialog and tracking the state - I'll dive into the data after a couple months and based on the numbers, we can decide if we want to implement a proper solution (unless we come up with a better solution before that). |
If we unsubscribe from it before we consume the "failed" event, then unless it's replaced by producers with "unknown" before "failed" event consumed in the Update VM, then it should work, IIC
👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
…'t load in time" This reverts commit 4a9f3bb.
Thanks for the review @samiuelson ! After follow up conversation on Slack we decided to add a delay to the state reset instead of just dismissing the dialog. The benefit of using the delay is that all users will understand why the update failed (due to low battery). It's a hacky workaround, but the value/effort ration is good. @kidinov Since you were able to reproduce the issue after the first "fix" (switch to the |
Version |
@malinajirka I missed the comment 😮💨 I'll retest it soon and update release notes too |
@kidinov Sorry, my bad, I should have followed up - it slipped my mind that this hasn't been merged yet. |
Generated by 🚫 Danger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Retested that on a real device and emulator - works fine. Merging to the release branch as a new beta will be cut off anyway
Closes: #12565
I haven't tested all the flows yet, I'm looking for initial thoughts about this solution @samiuelson @kidinov @AnirudhBhat. Do you think this change is safe for a beta fix or would be better to include it in the regular cycle?Description
The app currently incorrectly handles scenario when a required card reader update fails due to low battery during the connection flow.
This issue is caused by a race condition between the
Connect VM
<->SW Update VM
<->Stripe SDK updates
.The connect VM emits navigation event to move to the
SW Update VM
when the Stripe SDK starts na update. However, the app also asynchronously listens to Card Reader connection status here. Before the app gets a chance to navigate to the SW Update Dialog/VM, the Stripe SDK emitsNotConnected
event which resets the UpdateStatus to Unknown => when the SW Update Dialog/VM finally loads and starts listening to updates, the only status update it receives isUnknown
since the software update is no longer in progress - this results in an empty/white dialog being displayed (we don't display any UI for unknown state).The solution I propose is simplify the code and remove the race condition by listening to Card Reader updates on the main thread - this method doesn't do any heavy operations and reasoning about events that are performed in the order that they were emitted is much easier.
Unfortunately, this solution doesn't work in 100% of cases. The navigation component is asynchronous and sometimes the status changes to
Unknown
even with the above "fix".I implemented a workaround in the follow up commit that dismisses the empty/white dialog in such case and adds a flag (In the end, we decided to add an artificial delay that propagates the state to the UI after 500ms, "ensuring" the navigation component gets a chance to navigate to the Update flow in time.uiLoaded
) to the tracking event the app has been recording to indicate whether the dialog was dismissed before the UI was loaded. This avoids the UI glitch but users won't learn about the reason of the failure - we plan to keep an eye on the tracking event to understand how common is such scenario in production.Steps to reproduce
LOW_BATTERY_ERROR
.Testing information
Repeat the steps to reproduce, and notice the user is informed their card reader needs to be charged.
Also test connection to both HW readers as well as TTP reader to verify there isn't any regression. Last but not least, test if the successful SW update flow works as expected.
The tests that have been performed
I tested the connect/payment/update flow on the simulated readers, including TTP. I also tested connection/payment flows on a HW reader.
Images/gif
RELEASE-NOTES.txt
if necessary. Use the "[Internal]" label for non-user-facing changes.Reviewer (or Author, in the case of optional code reviews):
Please make sure these conditions are met before approving the PR, or request changes if the PR needs improvement: