Skip to content

Commit d2989e2

Browse files
committed
Wire cooldown.js into the model cascade: skip models known to be rate-limited, record a cooldown on 429
Before this, every callGenerateContent call restarted the cascade from GEMINI_MODEL fresh even if that exact model was 429'd seconds ago in a previous invocation -- wasting a quota-consuming request re-hitting it before falling through to the next model. Now the cascade checks isModelCoolingDown() before attempting each model (skipping straight past ones still in cooldown, best-effort via Redis) and calls setModelCooldown() with the parsed retry-delay when a 429 actually happens, so subsequent calls (this process or another, since Vercel doesn't guarantee warm reuse) benefit immediately. Still never sleeps/retries the same model inline -- only ever skips or falls through, same control flow shape as before.
1 parent 224a9a4 commit d2989e2

1 file changed

Lines changed: 16 additions & 3 deletions

File tree

connectors/gemini/client.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// ---------------------------------------------------------------------------
66

77
import { GEMINI_API_KEY, GEMINI_API, GEMINI_MODEL, GEMINI_FALLBACK_MODELS } from "../../config.js";
8+
import { isModelCoolingDown, setModelCooldown, parseRetryDelaySeconds } from "./cooldown.js";
89

910
async function callGenerateContentOnce(body, model) {
1011
if (!GEMINI_API_KEY) throw new Error("GEMINI_API_KEY is not set. Add it as an environment variable on the Manufact server.");
@@ -49,15 +50,27 @@ async function callGenerateContent(body, requestedModel) {
4950

5051
let lastErr;
5152
for (let i = 0; i < models.length; i++) {
53+
const model = models[i];
54+
// Best-effort cross-call memory (see cooldown.js): if this model was 429'd
55+
// recently -- possibly in a prior invocation, since Vercel doesn't
56+
// guarantee a warm/reused instance between calls -- skip it without
57+
// spending a request, same as if it had just failed with a fresh 429.
58+
if (await isModelCoolingDown(model)) {
59+
lastErr = lastErr || new Error(`Gemini API error (429): model "${model}" is in a recorded cooldown from a recent rate limit.`);
60+
continue;
61+
}
5262
try {
53-
const data = await callGenerateContentOnce(body, models[i]);
54-
if (i > 0) data._fallbackModelUsed = models[i]; // surfaced for logging/debugging, not required by callers
63+
const data = await callGenerateContentOnce(body, model);
64+
if (i > 0) data._fallbackModelUsed = model; // surfaced for logging/debugging, not required by callers
5565
return data;
5666
} catch (err) {
5767
lastErr = err;
5868
const isLast = i === models.length - 1;
5969
if (err.status !== 429 || isLast) throw err;
60-
// else: rate-limited on this model -- fall through to try the next one.
70+
// Rate-limited on this model -- record a cooldown (best-effort; never
71+
// blocks or throws on its own) so future calls can skip straight past
72+
// it, then fall through to try the next model as before.
73+
await setModelCooldown(model, parseRetryDelaySeconds(err.message));
6174
}
6275
}
6376
throw lastErr;

0 commit comments

Comments
 (0)