Files
OmniRoute/open-sse/handlers/chatCore/queueBudget.ts
Dizzle a152eb92db fix(resilience): stop unbounded queue that hangs 6min until Aborted (#12715)
Fila sem teto que segura a request seis minutos até o cliente abortar é pior que 503 imediato: consome slot, mascara a saturação e ainda entrega erro no fim. Um orçamento `maxWaitMs` por conexão compartilhado entre gate, slot padrão do provider e fila do Bottleneck é a forma certa — o teto tem que ser um só, senão cada camada espera o seu.

O `max(perConn, upstream)` no `executionMaxWaitMs` é o detalhe que evita a correção matar request em voo, que seria trocar um defeito por outro.

Registro a atribuição: você manteve o #12635 aberto para o @Tushar49 e creditou a percepção dele (providers lentos precisam de 2min→10min por conexão) enquanto adiciona o encanamento que faltava. É o jeito certo de construir sobre PR de outra pessoa sem tomar o crédito.

Sobre o `npm run lint` desmarcado com a nota do eslint quebrado no ambiente: deixar em branco e explicar vale mais que marcar sem ter rodado. Rodei aqui: limpo.

Revalidei sobre o tip: **13/13**, typecheck:core limpo, check-file-size OK. O `file-size-baseline.json` conflitou com os rebaselines desta campanha — resolvido aditivamente, JSON revalidado com `json.load`.
2026-09-10 10:49:34 -03:00

26 lines
1.1 KiB
TypeScript

import { isLocalStreamLifecycleError } from "@/shared/utils/circuitBreaker.ts";
import {
markLocalRateLimitError,
LEGACY_RATE_LIMIT_QUEUE_TIMEOUT_CODE,
} from "../../services/rateLimitManager/errors.ts";
/**
* Rethrow a hierarchical-admission failure. Aborts, stream-lifecycle errors and coded
* semaphore errors pass through unchanged (SEMAPHORE_QUEUE_FULL is a 429 admission signal
* the combo cascade reads); only a bare time-budget timeout becomes the LEGACY queue 503.
*/
export function rethrowAdmissionError(error: unknown): never {
const err = error as { name?: unknown; code?: unknown } | null;
if (err?.name === "AbortError" || err?.code === "ABORT_ERR") throw error;
if (isLocalStreamLifecycleError(error)) throw error;
if (err?.code === undefined) {
throw markLocalRateLimitError(error as Error, LEGACY_RATE_LIMIT_QUEUE_TIMEOUT_CODE);
}
throw error;
}
/** What is left of a queue-wait budget that started at `startedAt`. */
export function remainingQueueBudgetMs(budgetMs: number, startedAt: number): number {
return Math.max(0, budgetMs - (Date.now() - startedAt));
}