-
Notifications
You must be signed in to change notification settings - Fork 130
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
An attempt to fix a crash in the Dashboard Performance card #12605
Conversation
Generated by 🚫 Danger |
📲 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.
|
Previously, we were assigning the charts value to itself, and it was making the logic harder to follow.
328f851
to
40b4638
Compare
chartRevenueStats = revenueStats | ||
val entries = chartRevenueStats.values.mapIndexed { index, value -> | ||
val entries = revenueStats.values.mapIndexed { index, value -> |
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.
This change is not related to the fix, but it's something that I noticed and that confused me and lost me a lot of time while checking if it could be the cause of the issue: we were assigning chartRevenueStats
to itself here, and while investigating the issue I was looking for any race modifications to the chartRevenueStats
that could explain the issue.
To avoid this confusion in the future, I'm simplifying the logic here, it's still the same just without the useless assignment.
@@ -552,6 +552,7 @@ class DashboardStatsView @JvmOverloads constructor( | |||
fadeInLabelValue(ordersValue, orders) | |||
|
|||
if (chartRevenueStats.isEmpty() || revenueStatsModel?.totalSales == 0.toDouble()) { | |||
binding.chart.clear() |
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.
Hey @hichamboushaba, thanks for investigating this.
The explanation for the possible cause of the crash makes sense. However, I can't think of a scenario where given a date range, there's cached revenue data for it, but when requesting fresh data for the same range, the revenue data is empty.
I suspect that the logic enabled here might be messing around with the cached values, leading to this empty data. The reason I think this is because:
- Crashes started happening from
19.8
which is when this feature was enabled - Upon checking the app logs for several of the users impacted by the crash I can see that always leading to the crash before opening the app there's one of these 2 logs:
🔵 Tracked: background_data_sync_error, Properties: {"error_context":"UpdateDataOnBackgroundWorker","error_description":"Dashboard stats refresh failed." ...
🔵 Tracked: background_data_synced, Properties: {"time_taken":25409,"blog_id":236595758, ...
Thinking out loud here. Could it be that this is happening?
- User loads successfully revenue data. Chart is displayed.
- User sends app to the background
- A background stats refresh is triggered. This clears the cached data because it fails or whatever reason.
- User brings the app to the foreground, ViewModel still has the
viewState
in memory, but the cache for the selected date range is empty now. Chart will be displayed, and then empty revenue data will be passedtoDashboardStatsView
Aside from that hypothesis. And looking at the proposed way to mitigate the crash I was thinking of a different way of resolving it, without clearing the chart, and keeping the cached data visible. Just avoid updating the view completely if the reneue stats model is empty.
Subject: [PATCH] Avoid updating the view
---
Index: WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsView.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsView.kt
--- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsView.kt (revision 40b46384d60a12e8beffa7f0fae562239b6c6917)
+++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/dashboard/stats/DashboardStatsView.kt (date 1726593414406)
@@ -378,6 +378,11 @@
}
fun updateView(revenueStatsModel: RevenueStatsUiModel?) {
+ if (revenueStatsModel?.rangeId == this.revenueStatsModel?.rangeId &&
+ revenueStatsModel?.intervalList.isNullOrEmpty()
+ ) {
+ return
+ }
this.revenueStatsModel = revenueStatsModel
// There are times when the stats v4 api returns no grossRevenue or ordersCount for a site
@@ -552,7 +557,6 @@
fadeInLabelValue(ordersValue, orders)
if (chartRevenueStats.isEmpty() || revenueStatsModel?.totalSales == 0.toDouble()) {
- binding.chart.clear()
isRequestingStats = false
return
}
@@ -726,6 +730,7 @@
dateString,
statsTimeRangeSelection.revenueStatsGranularity
)
+
else -> error("Unsupported range value used in my store tab: ${statsTimeRangeSelection.selectionType}")
}.also { result -> trackUnexpectedFormat(result, dateString) }
}
It feel like a workaround, but at least the user won't be seeing empty results for an interval the previously did show some revenue results.
Wdyt?
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.
Thanks @JorgeMucientes for the great analysis, let me try to respond to some points below, and we'll take it from there.
However, I can't think of a scenario where given a date range, there's cached revenue data for it, but when requesting fresh data for the same range, the revenue data is empty.
It can happen if an order gets deleted.
This clears the cached data because it fails or whatever reason.
Looking at the code, I don't think that failures could trigger clearing the data, only a success would.
And looking at the proposed way to mitigate the crash I was thinking of a different way of resolving it, without clearing the chart, and keeping the cached data visible
My issue with this is that if our theory is right, we are actually displaying outdated data here, so clearing the chart is still the correct thing to do to avoid displaying wrong data.
Please let me know what you think.
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.
Thanks for the clarifications @hichamboushaba
It can happen if an order gets deleted.
True! Had not considered that case.
My issue with this is that if our theory is right, we are actually displaying outdated data here, so clearing the chart is still the correct thing to do to avoid displaying wrong data.
Fair enough. Let's keep the current approach, then.
Closes: #12548
Please don't merge yet, I'll add a release notes entry later.
Description
This PR is an attempt to fix a crash in the performance card. I'm not 100% certain this is the situation that the users face, but it's the only way I found where I was able to reproduce the crash.
And this is what happens according to my theory:
Using the cached data followed up with a fetch is a new behavior that we added recently (precisely as part of 19.6), and I think this could explain why the crash started happening just now.
@JorgeMucientes given your experience with the stats, I'm assigning you this for review 🙏
Steps to reproduce the crash
trunk
Confirm the fix
Patch
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: