From 36f8a8ce1692c5db7cb157154eaf8aabc4a28658 Mon Sep 17 00:00:00 2001 From: "luongquocloc8668@gmail.com" Date: Mon, 9 Mar 2026 17:36:16 +0700 Subject: [PATCH] feat(base): add 429 retry with fixed delay for all providers Retry up to 2 times with 2s delay before falling back to next URL. Made-with: Cursor --- open-sse/config/constants.js | 6 ++++++ open-sse/executors/base.js | 14 +++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/open-sse/config/constants.js b/open-sse/config/constants.js index 801c2db..e5d15ad 100644 --- a/open-sse/config/constants.js +++ b/open-sse/config/constants.js @@ -461,6 +461,12 @@ export const DEFAULT_MAX_TOKENS = 64000; // Minimum max tokens for tool calling (to prevent truncated arguments) export const DEFAULT_MIN_TOKENS = 32000; +// Retry config for 429 responses (used by BaseExecutor) +export const RETRY_CONFIG = { + maxAttempts: 2, + delayMs: 2000 +}; + // HTTP status codes export const HTTP_STATUS = { BAD_REQUEST: 400, diff --git a/open-sse/executors/base.js b/open-sse/executors/base.js index ab3f7d2..7fc9649 100644 --- a/open-sse/executors/base.js +++ b/open-sse/executors/base.js @@ -1,4 +1,4 @@ -import { HTTP_STATUS } from "../config/constants.js"; +import { HTTP_STATUS, RETRY_CONFIG } from "../config/constants.js"; import { proxyAwareFetch } from "../utils/proxyFetch.js"; /** @@ -80,12 +80,15 @@ export class BaseExecutor { const fallbackCount = this.getFallbackCount(); let lastError = null; let lastStatus = 0; + const retryAttemptsByUrl = {}; for (let urlIndex = 0; urlIndex < fallbackCount; urlIndex++) { const url = this.buildUrl(model, stream, urlIndex, credentials); const headers = this.buildHeaders(credentials, stream); const transformedBody = this.transformRequest(model, body, stream, credentials); + if (!retryAttemptsByUrl[urlIndex]) retryAttemptsByUrl[urlIndex] = 0; + try { const response = await proxyAwareFetch(url, { method: "POST", @@ -94,6 +97,15 @@ export class BaseExecutor { signal }, proxyOptions); + // Retry 429 with fixed delay before falling back to next URL + if (response.status === HTTP_STATUS.RATE_LIMITED && retryAttemptsByUrl[urlIndex] < RETRY_CONFIG.maxAttempts) { + retryAttemptsByUrl[urlIndex]++; + log?.debug?.("RETRY", `429 retry ${retryAttemptsByUrl[urlIndex]}/${RETRY_CONFIG.maxAttempts} after ${RETRY_CONFIG.delayMs / 1000}s`); + await new Promise(resolve => setTimeout(resolve, RETRY_CONFIG.delayMs)); + urlIndex--; + continue; + } + if (this.shouldRetry(response.status, urlIndex)) { log?.debug?.("RETRY", `${response.status} on ${url}, trying fallback ${urlIndex + 1}`); lastStatus = response.status;