feat(resilience): expose providerQuotaOverrides via /api/resilience (#9871)

Co-authored-by: herjarsa <herjarsa@users.noreply.github.com>
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-08-09 09:54:17 -03:00
committed by GitHub
parent c8e6b07df5
commit bd33b4589a
3 changed files with 175 additions and 3 deletions

View File

@@ -111,9 +111,15 @@ function normalizeLegacyPatch(body: JsonRecord): ResilienceSettingsPatch {
}
async function syncRuntimeSettings(resilienceSettings: ResilienceSettings) {
const { applyRequestQueueSettings } =
await import("@omniroute/open-sse/services/rateLimitManager");
const [{ applyRequestQueueSettings }, { setProviderQuotaOverrides }] = await Promise.all([
import("@omniroute/open-sse/services/rateLimitManager"),
import("@omniroute/open-sse/services/providerDefaultRateLimit"),
]);
await applyRequestQueueSettings(resilienceSettings.requestQueue);
// #6846 Phase 2: re-apply per-provider RPM/concurrency overrides on the hot
// path so a PATCH takes effect without a process restart. Mirrors the call in
// rateLimitManager.ts::initializeRateLimits() (startup).
setProviderQuotaOverrides(resilienceSettings.providerQuotaOverrides);
}
/**
@@ -136,6 +142,7 @@ export async function GET() {
comboCooldownWait: resilience.comboCooldownWait,
quotaShareConcurrencyLimit: resilience.quotaShareConcurrencyLimit,
providerCooldown: resilience.providerCooldown,
providerQuotaOverrides: resilience.providerQuotaOverrides,
legacy: buildLegacyResilienceCompat(resilience),
});
} catch (err: unknown) {
@@ -208,6 +215,12 @@ export async function PATCH(request) {
providerCooldown: body.providerCooldown as ResilienceSettingsPatch["providerCooldown"],
}
: {}),
...(body.providerQuotaOverrides
? {
providerQuotaOverrides:
body.providerQuotaOverrides as ResilienceSettingsPatch["providerQuotaOverrides"],
}
: {}),
...normalizeLegacyPatch(body),
});
@@ -245,6 +258,7 @@ export async function PATCH(request) {
comboCooldownWait: nextResilience.comboCooldownWait,
quotaShareConcurrencyLimit: nextResilience.quotaShareConcurrencyLimit,
providerCooldown: nextResilience.providerCooldown,
providerQuotaOverrides: nextResilience.providerQuotaOverrides,
legacy: buildLegacyResilienceCompat(nextResilience),
});
} catch (err: unknown) {

View File

@@ -158,6 +158,21 @@ export const updateResilienceSchema = z
.strict()
.optional(),
defaults: legacyResilienceDefaultsSchema.optional(),
// #6846 Phase 2: per-provider operator overrides for the header-less
// "provider default" static budget (open-sse/services/providerDefaultRateLimit.ts)
// and its companion per-connection concurrency cap. Mirrors
// ProviderQuotaOverrideSettings in src/lib/resilience/settings/types.ts.
providerQuotaOverrides: z
.record(
z.string().min(1),
z
.object({
rpm: z.number().int().min(1).optional(),
concurrency: z.number().int().min(1).optional(),
})
.strict()
)
.optional(),
})
.strict()
.superRefine((value, ctx) => {
@@ -170,7 +185,8 @@ export const updateResilienceSchema = z
!value.quotaShareConcurrencyLimit &&
!value.providerCooldown &&
!value.profiles &&
!value.defaults
!value.defaults &&
!value.providerQuotaOverrides
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,

View File

@@ -0,0 +1,142 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import {
DEFAULT_RESILIENCE_SETTINGS,
mergeResilienceSettings,
resolveResilienceSettings,
type ResilienceSettings,
} from "../../src/lib/resilience/settings.ts";
import { updateResilienceSchema } from "../../src/shared/validation/schemas.ts";
function cloneDefaults(): ResilienceSettings {
return structuredClone(DEFAULT_RESILIENCE_SETTINGS);
}
// --- Schema (PATCH /api/resilience body) ---
test("updateResilienceSchema accepts providerQuotaOverrides entries", () => {
const parsed = updateResilienceSchema.safeParse({
providerQuotaOverrides: {
minimax: { rpm: 30, concurrency: 4 },
nvidia: { rpm: 60 },
},
});
assert.equal(parsed.success, true, "valid override map should parse");
});
test("updateResilienceSchema allows a body containing only providerQuotaOverrides", () => {
// The superRefine requires at least one field; a lone override map is a
// legitimate update and must not trigger "Must provide resilience settings".
const parsed = updateResilienceSchema.safeParse({
providerQuotaOverrides: { minimax: { rpm: 30 } },
});
assert.equal(parsed.success, true);
});
test("updateResilienceSchema rejects non-positive rpm/concurrency", () => {
assert.equal(
updateResilienceSchema.safeParse({
providerQuotaOverrides: { minimax: { rpm: 0 } },
}).success,
false,
"rpm must be >= 1"
);
assert.equal(
updateResilienceSchema.safeParse({
providerQuotaOverrides: { minimax: { concurrency: -1 } },
}).success,
false,
"concurrency must be >= 1"
);
});
test("updateResilienceSchema rejects unknown keys inside an override entry", () => {
assert.equal(
updateResilienceSchema.safeParse({
providerQuotaOverrides: { minimax: { rpm: 30, windowMs: 60_000 } },
}).success,
false,
"override entries are .strict() — unknown keys rejected"
);
});
// --- mergeResilienceSettings ---
test("mergeResilienceSettings stores provider quota overrides", () => {
const next = mergeResilienceSettings(cloneDefaults(), {
providerQuotaOverrides: {
minimax: { rpm: 30, concurrency: 4 },
},
});
assert.deepEqual(next.providerQuotaOverrides, { minimax: { rpm: 30, concurrency: 4 } });
});
test("mergeResilienceSettings preserves existing overrides when patch omits the map", () => {
const current = mergeResilienceSettings(cloneDefaults(), {
providerQuotaOverrides: { nvidia: { rpm: 40 } },
});
const next = mergeResilienceSettings(current, {
requestQueue: { maxWaitMs: 60_000 },
});
assert.deepEqual(next.providerQuotaOverrides, { nvidia: { rpm: 40 } });
});
test("mergeResilienceSettings drops invalid override entries via normalization", () => {
const next = mergeResilienceSettings(cloneDefaults(), {
providerQuotaOverrides: {
minimax: { rpm: 0 }, // non-positive → dropped by normalizeProviderQuotaOverrideEntry
} as never,
});
assert.deepEqual(next.providerQuotaOverrides, {});
});
// --- resolveResilienceSettings round-trip ---
test("resolveResilienceSettings round-trips stored provider quota overrides", () => {
const resolved = resolveResilienceSettings({
resilienceSettings: {
providerQuotaOverrides: {
minimax: { rpm: 30, concurrency: 4 },
},
},
});
assert.deepEqual(resolved.providerQuotaOverrides, { minimax: { rpm: 30, concurrency: 4 } });
});
// --- Route wiring (GET/PATCH response + hot reload) ---
const RESILIENCE_ROUTE_PATH = path.resolve(process.cwd(), "src/app/api/resilience/route.ts");
test("GET /api/resilience returns providerQuotaOverrides", () => {
const source = fs.readFileSync(RESILIENCE_ROUTE_PATH, "utf8");
assert.match(
source,
/providerQuotaOverrides:\s*resilience\.providerQuotaOverrides\b/,
"GET response should expose the resolved override map"
);
});
test("PATCH /api/resilience returns providerQuotaOverrides and propagates it into the merge", () => {
const source = fs.readFileSync(RESILIENCE_ROUTE_PATH, "utf8");
assert.match(
source,
/providerQuotaOverrides:\s*nextResilience\.providerQuotaOverrides\b/,
"PATCH response should expose the merged override map"
);
assert.match(
source,
/body\.providerQuotaOverrides/,
"PATCH should read providerQuotaOverrides from the validated body"
);
});
test("syncRuntimeSettings re-applies provider quota overrides on the hot path", () => {
const source = fs.readFileSync(RESILIENCE_ROUTE_PATH, "utf8");
assert.match(
source,
/setProviderQuotaOverrides\(resilienceSettings\.providerQuotaOverrides\)/,
"PATCH should hot-reload overrides without a process restart"
);
});