mirror of
https://github.com/decolua/9router.git
synced 2026-05-08 12:01:28 +00:00
fix: enhance retry logic and configuration for HTTP status codes
This commit is contained in:
@@ -45,8 +45,9 @@ export const RETRY_CONFIG = {
|
||||
// Backward compat: if value is a number, treated as attempts with RETRY_CONFIG.delayMs
|
||||
export const DEFAULT_RETRY_CONFIG = {
|
||||
429: { attempts: 0, delayMs: 0 },
|
||||
502: { attempts: 1, delayMs: 3000 },
|
||||
503: { attempts: 1, delayMs: 2000 }
|
||||
502: { attempts: 3, delayMs: 3000 },
|
||||
503: { attempts: 3, delayMs: 2000 },
|
||||
504: { attempts: 2, delayMs: 3000 }
|
||||
};
|
||||
|
||||
// Normalize a retry entry to { attempts, delayMs }
|
||||
|
||||
@@ -108,6 +108,16 @@ export class BaseExecutor {
|
||||
// Merge default retry config with provider-specific config
|
||||
const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...this.config.retry };
|
||||
|
||||
// Schedule retry via retryConfig[statusKey]. Returns true when caller should `urlIndex--; continue`
|
||||
const tryRetry = async (urlIndex, statusKey, reason) => {
|
||||
const { attempts, delayMs } = resolveRetryEntry(retryConfig[statusKey]);
|
||||
if (attempts <= 0 || retryAttemptsByUrl[urlIndex] >= attempts) return false;
|
||||
retryAttemptsByUrl[urlIndex]++;
|
||||
log?.debug?.("RETRY", `${reason} retry ${retryAttemptsByUrl[urlIndex]}/${attempts} after ${delayMs / 1000}s`);
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
return true;
|
||||
};
|
||||
|
||||
for (let urlIndex = 0; urlIndex < fallbackCount; urlIndex++) {
|
||||
const url = this.buildUrl(model, stream, urlIndex, credentials);
|
||||
const transformedBody = this.transformRequest(model, body, stream, credentials);
|
||||
@@ -123,15 +133,7 @@ export class BaseExecutor {
|
||||
signal
|
||||
}, proxyOptions);
|
||||
|
||||
// Retry based on status code config
|
||||
const { attempts: maxRetries, delayMs } = resolveRetryEntry(retryConfig[response.status]);
|
||||
if (maxRetries > 0 && retryAttemptsByUrl[urlIndex] < maxRetries) {
|
||||
retryAttemptsByUrl[urlIndex]++;
|
||||
log?.debug?.("RETRY", `${response.status} retry ${retryAttemptsByUrl[urlIndex]}/${maxRetries} after ${delayMs / 1000}s`);
|
||||
await new Promise(resolve => setTimeout(resolve, delayMs));
|
||||
urlIndex--;
|
||||
continue;
|
||||
}
|
||||
if (await tryRetry(urlIndex, response.status, `status ${response.status}`)) { urlIndex--; continue; }
|
||||
|
||||
if (this.shouldRetry(response.status, urlIndex)) {
|
||||
log?.debug?.("RETRY", `${response.status} on ${url}, trying fallback ${urlIndex + 1}`);
|
||||
@@ -142,6 +144,11 @@ export class BaseExecutor {
|
||||
return { response, url, headers, transformedBody };
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
if (error.name === "AbortError") throw error;
|
||||
|
||||
// Map network/fetch exceptions to 502 retry config
|
||||
if (await tryRetry(urlIndex, HTTP_STATUS.BAD_GATEWAY, `network "${error.message}"`)) { urlIndex--; continue; }
|
||||
|
||||
if (urlIndex + 1 < fallbackCount) {
|
||||
log?.debug?.("RETRY", `Error on ${url}, trying fallback ${urlIndex + 1}`);
|
||||
continue;
|
||||
|
||||
Reference in New Issue
Block a user