From 17bdba8197f0c54a58554ab188414b1da538cfdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20M=C3=A4ki?= Date: Thu, 20 Jun 2024 13:14:38 +0300 Subject: [PATCH] Turn off background updates after failures and reduce logging Thunderstore's Sentry logs are full of reports where the background update fails time and time again. While this is a sort of inverse survivor bias, it's probably safe to assume that once the background updates start failing, they're unlikely to start working again. So turn off the background updates instead. When the background updates are turned off, an error modal is shown. I couldn't think of a better way to notify the user about the mod manager suddenly going "offline". There's a change that making the background update failure visible to users this way causes a flood of support requests. If the failure was due to network error or the request timing out, the errors are omitted. Currently these two are number 3 and 4 on Thunderstore's Sentry, and they're just noise since we can't do ~anything about them. Other errors, e.g. related to caching the package list to IndexedDB are still logged in the hopes that we can figure out how to solve at least some of them. --- src/components/mixins/UtilityMixin.vue | 29 +++++++++++++++++++++++--- src/utils/HttpUtils.ts | 6 ++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/components/mixins/UtilityMixin.vue b/src/components/mixins/UtilityMixin.vue index 3571e19aa..d61e70aa1 100644 --- a/src/components/mixins/UtilityMixin.vue +++ b/src/components/mixins/UtilityMixin.vue @@ -5,14 +5,19 @@ import Component from 'vue-class-component'; import R2Error from '../../model/errors/R2Error'; import CdnProvider from '../../providers/generic/connection/CdnProvider'; import ConnectionProvider from '../../providers/generic/connection/ConnectionProvider'; +import { isCanceledByRequest, isNetworkError } from '../../utils/HttpUtils'; @Component export default class UtilityMixin extends Vue { readonly REFRESH_INTERVAL = 5 * 60 * 1000; private tsRefreshFailed = false; + private tsRefreshInterval: NodeJS.Timeout|undefined; hookThunderstoreModListRefresh() { - setInterval(this.tryRefreshThunderstoreModList, this.REFRESH_INTERVAL); + this.tsRefreshInterval = setInterval( + this.tryRefreshThunderstoreModList, + this.REFRESH_INTERVAL + ); } async refreshThunderstoreModList() { @@ -48,8 +53,26 @@ export default class UtilityMixin extends Vue { await this.refreshThunderstoreModList(); } catch (e) { if (this.tsRefreshFailed) { - console.error("Two consecutive background refresh attempts failed"); - throw e; + // Turn off the background update process after two consecutive + // attempts have failed, as assumably further retries would just + // drain resources and possibly cause other issues with little + // hope of succeeding. + clearInterval(this.tsRefreshInterval); + this.tsRefreshInterval = undefined; + + this.$store.commit("error/handleError", new R2Error( + "Background updates halted", + `Two consecutive attempts to update the online mod list on the + background have failed, and the background update has been + disabled. You can continue to use the app, but the online mod + list won't be updated automatically anymore. Error code: "${e}"`, + "Restart the app to reactivate the background update." + )); + + // Rethrow non-trivial errors to get them logged. + if (!isCanceledByRequest(e) && !isNetworkError(e)) { + throw e; + } } this.tsRefreshFailed = true; diff --git a/src/utils/HttpUtils.ts b/src/utils/HttpUtils.ts index 1be34a0ad..367254b69 100644 --- a/src/utils/HttpUtils.ts +++ b/src/utils/HttpUtils.ts @@ -102,6 +102,12 @@ export const makeLongRunningGetRequest = async ( export const isNetworkError = (responseOrError: unknown) => responseOrError instanceof Error && responseOrError.message === "Network Error"; +/** + * Is the request canceled by the AbortController like the one used by makeLongRunningGetRequest? + */ +export const isCanceledByRequest = (responseOrError: unknown) => + axios.isCancel(responseOrError); + /** * Is the Error thrown by Axios request caused by a response timeout? */