From 7ce62cb77cbfe360f7dd32432b43d6f556ce7984 Mon Sep 17 00:00:00 2001 From: Roman Sharkov Date: Mon, 4 May 2026 14:44:17 +0200 Subject: [PATCH] fix(fetch): Apply backoff to HTTP error retries retry='error' on 5xx scheduled retries without scaling the interval, incrementing the counter, or dispatching retries-failed. Only the network-error path did. Extract a scheduleRetry helper and dispatch RETRYING from the HTTP-error branch too. Fixes retryMaxCount/retryScaler being ignored on 500. --- library/src/plugins/actions/fetch.ts | 29 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/library/src/plugins/actions/fetch.ts b/library/src/plugins/actions/fetch.ts index 91a789e9..5047ff96 100644 --- a/library/src/plugins/actions/fetch.ts +++ b/library/src/plugins/actions/fetch.ts @@ -520,6 +520,18 @@ const fetchEventSource = ( let retries = 0 let baseRetryInterval = retryInterval + const scheduleRetry = (interval: number = retryInterval): boolean => { + clearTimeout(retryTimer) + retryTimer = setTimeout(create, interval) + retryInterval = Math.min(retryInterval * retryScaler, retryMaxWait) + if (++retries >= retryMaxCount) { + dispatchFetch(RETRIES_FAILED, el, {}) + dispose() + reject('Max retries reached.') + return false + } + return true + } const create = async () => { curRequestController = new AbortController() const curRequestSignal = curRequestController.signal @@ -569,8 +581,8 @@ const fetchEventSource = ( !isRedirectStatus && (retry === 'always' || (retry === 'error' && isErrorStatus)) ) { - clearTimeout(retryTimer) - retryTimer = setTimeout(create, retryInterval) + dispatchFetch(RETRYING, el, { status: status.toString() }) + scheduleRetry() return } dispose() @@ -662,18 +674,7 @@ const fetchEventSource = ( try { // check if we need to retry: const interval: any = onerror?.(err) || retryInterval - clearTimeout(retryTimer) - retryTimer = setTimeout(create, interval) - retryInterval = Math.min( - retryInterval * retryScaler, - retryMaxWait, - ) // exponential backoff - if (++retries >= retryMaxCount) { - dispatchFetch(RETRIES_FAILED, el, {}) - // we should not retry anymore: - dispose() - reject('Max retries reached.') // Max retries reached, check your server or network connection - } else { + if (scheduleRetry(interval)) { console.error( `Datastar failed to reach ${input.toString()} retrying in ${interval}ms.`, )