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? */