Files
OmniRoute/tests/unit/accountSemaphore.test.ts
Diego Rodrigues de Sa e Souza a179ffed5b feat(resilience): add hierarchical concurrency admission (#11493)
Cherry-pick of the 3 value commits from #11323 (by @RaviTharuma), dropping 17 already-merged rebase-baggage commits. Validated in a combined-batch worktree off release/v3.8.51 tip:
- typecheck:core, file-size, changelog-integrity, complexity, cognitive-complexity gates — all OK
- Focused tests, isolated re-run flake-free: accountSemaphore.test.ts 11/11, chatcore-hierarchical-admission.test.ts 2/2, resilience-settings-provider-quota-overrides.test.ts 12/12, i18n-vi-completeness.test.ts 5/5
- lint clean once isolated from the unrelated ESLint-10 suppressions regression carried by a separate PR in the batch

Closes #7778. Full credit to @RaviTharuma for the design and implementation.
2026-08-25 07:19:09 -03:00

282 lines
8.4 KiB
TypeScript

import assert from "node:assert/strict";
import { afterEach, describe, it } from "node:test";
import {
acquire,
acquireMany,
buildAccountSemaphoreKey,
getStats,
markBlocked,
reset,
resetAll,
} from "../../open-sse/services/accountSemaphore";
afterEach(() => {
resetAll();
});
describe("accountSemaphore acquireMany", () => {
it("atomically acquires every enabled gate and releases them once", async () => {
const release = await acquireMany([
{ key: "global", maxConcurrency: 2 },
{ key: "provider:codex", maxConcurrency: 1 },
{ key: "account:codex:one", maxConcurrency: 1 },
{ key: "disabled", maxConcurrency: 0 },
]);
assert.deepEqual(getStats(), {
global: { running: 1, queued: 0, maxConcurrency: 2, blockedUntil: null },
"provider:codex": { running: 1, queued: 0, maxConcurrency: 1, blockedUntil: null },
"account:codex:one": { running: 1, queued: 0, maxConcurrency: 1, blockedUntil: null },
});
release();
release();
await new Promise((resolve) => setTimeout(resolve, 10));
assert.deepEqual(getStats(), {});
});
it("queues one atomic request without partially reserving free gates", async () => {
const releaseProvider = await acquire("provider:codex", { maxConcurrency: 1 });
const waiting = acquireMany(
[
{ key: "global", maxConcurrency: 1 },
{ key: "provider:codex", maxConcurrency: 1 },
{ key: "account:codex:two", maxConcurrency: 1 },
],
{ timeoutMs: 200 }
);
await new Promise((resolve) => setTimeout(resolve, 10));
assert.equal(getStats().global?.running ?? 0, 0);
assert.equal(getStats()["account:codex:two"]?.running ?? 0, 0);
assert.equal(getStats()["provider:codex"]?.queued, 1);
releaseProvider();
const release = await waiting;
assert.equal(getStats().global?.running, 1);
assert.equal(getStats()["provider:codex"]?.running, 1);
assert.equal(getStats()["account:codex:two"]?.running, 1);
release();
});
it("removes an atomic waiter from every gate on abort", async () => {
const releaseGlobal = await acquire("global", { maxConcurrency: 1 });
const controller = new AbortController();
const waiting = acquireMany(
[
{ key: "global", maxConcurrency: 1 },
{ key: "provider:codex", maxConcurrency: 1 },
],
{ signal: controller.signal, timeoutMs: 200 }
);
await new Promise((resolve) => setTimeout(resolve, 10));
controller.abort();
await assert.rejects(waiting, { name: "AbortError" });
assert.equal(getStats().global?.queued, 0);
assert.equal(getStats()["provider:codex"]?.queued ?? 0, 0);
releaseGlobal();
});
it("times out an atomic waiter without leaking reservations", async () => {
const releaseGlobal = await acquire("global", { maxConcurrency: 1 });
await assert.rejects(
acquireMany(
[
{ key: "global", maxConcurrency: 1 },
{ key: "provider:codex", maxConcurrency: 1 },
],
{ timeoutMs: 10 }
),
(error: Error & { code?: string }) => error.code === "SEMAPHORE_TIMEOUT"
);
assert.equal(getStats().global?.queued, 0);
assert.equal(getStats()["provider:codex"]?.running ?? 0, 0);
releaseGlobal();
});
it("rejects an atomic waiter when any required gate queue is full", async () => {
const releaseGlobal = await acquire("global", { maxConcurrency: 1 });
const queued = acquire("global", { maxConcurrency: 1, maxQueueSize: 1, timeoutMs: 200 });
await new Promise((resolve) => setTimeout(resolve, 10));
await assert.rejects(
acquireMany(
[
{ key: "global", maxConcurrency: 1 },
{ key: "provider:codex", maxConcurrency: 1 },
],
{ maxQueueSize: 1, timeoutMs: 200 }
),
(error: Error & { code?: string }) => error.code === "SEMAPHORE_QUEUE_FULL"
);
assert.equal(getStats()["provider:codex"]?.queued ?? 0, 0);
releaseGlobal();
(await queued)();
});
});
describe("accountSemaphore", async () => {
it("queues requests beyond the account cap and drains on release", async () => {
const key = buildAccountSemaphoreKey({
provider: "alibaba",
accountKey: "acct-1",
});
const releaseA = await acquire(key, { maxConcurrency: 2, timeoutMs: 200 });
const releaseB = await acquire(key, { maxConcurrency: 2, timeoutMs: 200 });
const queued = acquire(key, { maxConcurrency: 2, timeoutMs: 200 });
await new Promise((resolve) => setTimeout(resolve, 10));
assert.deepEqual(getStats()[key], {
running: 2,
queued: 1,
maxConcurrency: 2,
blockedUntil: null,
});
releaseA();
const releaseC = await queued;
assert.deepEqual(getStats()[key], {
running: 2,
queued: 0,
maxConcurrency: 2,
blockedUntil: null,
});
releaseA();
releaseB();
releaseC();
await new Promise((resolve) => setTimeout(resolve, 10));
assert.equal(getStats()[key], undefined);
});
it("returns a no-op release when concurrency is bypassed", async () => {
const key = buildAccountSemaphoreKey({
provider: "alibaba",
accountKey: "acct-bypass",
});
const release = await acquire(key, { maxConcurrency: 0, timeoutMs: 50 });
assert.deepEqual(getStats(), {});
release();
await new Promise((resolve) => setTimeout(resolve, 10));
assert.equal(getStats()[key], undefined);
});
it("uses SEMAPHORE_TIMEOUT for timed out queued requests", async () => {
const key = buildAccountSemaphoreKey({
provider: "alibaba",
accountKey: "acct-timeout",
});
const releaseA = await acquire(key, { maxConcurrency: 1, timeoutMs: 200 });
const queued = acquire(key, { maxConcurrency: 1, timeoutMs: 200 });
const keepAlive = setTimeout(() => {}, 250);
try {
await queued;
assert.fail("Expected timeout error");
} catch (err: unknown) {
assert.ok(err instanceof Error);
const error = err as Error & { code?: string };
assert.equal(error.code, "SEMAPHORE_TIMEOUT");
} finally {
clearTimeout(keepAlive);
}
releaseA();
await new Promise((resolve) => setTimeout(resolve, 10));
assert.equal(getStats()[key], undefined);
});
it("keeps release idempotent for finally blocks", async () => {
const key = buildAccountSemaphoreKey({
provider: "alibaba",
accountKey: "acct-idempotent",
});
const releaseA = await acquire(key, { maxConcurrency: 1, timeoutMs: 200 });
// Simulate a finally block calling release twice
releaseA();
releaseA();
releaseA();
// The second acquire should succeed immediately (slot was released)
const releaseB = await acquire(key, { maxConcurrency: 1, timeoutMs: 200 });
assert.deepEqual(getStats()[key], {
running: 1,
queued: 0,
maxConcurrency: 1,
blockedUntil: null,
});
releaseB();
await new Promise((resolve) => setTimeout(resolve, 10));
assert.equal(getStats()[key], undefined);
});
it("supports temporary blocking and explicit reset hooks", async () => {
const key = buildAccountSemaphoreKey({
provider: "alibaba",
accountKey: "acct-blocked",
});
await acquire(key, { maxConcurrency: 1, timeoutMs: 200 });
assert.deepEqual(getStats()[key], {
running: 1,
queued: 0,
maxConcurrency: 1,
blockedUntil: null,
});
markBlocked(key, 50);
// Should block even though slot is available
const acquired = acquire(key, { maxConcurrency: 1, timeoutMs: 100 });
await new Promise((resolve) => setTimeout(resolve, 30));
// Should still be queued because the gate is blocked
const stats = getStats()[key];
assert.equal(stats.running, 1);
assert.equal(stats.queued, 1);
assert.equal(stats.maxConcurrency, 1);
assert.ok(stats.blockedUntil !== null, "blockedUntil should be set");
reset(key);
await assert.rejects(async () => {
await acquired;
});
});
it("preserves existing maxConcurrency when markBlocked is applied", async () => {
const key = buildAccountSemaphoreKey({
provider: "alibaba",
accountKey: "acct-preserve",
});
await acquire(key, { maxConcurrency: 2, timeoutMs: 200 });
markBlocked(key, 50);
const stats = getStats()[key];
assert.equal(stats.running, 1);
assert.equal(stats.queued, 0);
assert.equal(stats.maxConcurrency, 2);
assert.ok(stats.blockedUntil !== null, "blockedUntil should be set");
});
});