Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/dashboard/public/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1421,7 +1421,8 @@ async function renderFailoverTuning() {
<span class="chip chip-red" title="Server-side failure. Always feeds the breaker (streak + window). An exact 500 on Zen chat also triggers one translated retry via /responses on the same key.">5xx feeds breaker</span>
<span class="chip chip-yellow" title="Burst rate limit (no quota markers). Returned to the client verbatim — no same-request key-burning — but counts toward the breaker when Burst-failover is on, so the NEXT request spills.">burst-429 feeds breaker</span>
<span class="chip chip-yellow" title="Quota exhaustion (402, or 429 with quota markers). Parks the key in cooldown for the upstream-supplied wait and fails over to the next key within the SAME request.">quota-429 → cooldown + failover</span>
<span class="chip chip-muted" title="400/403/404 and similar (dashboard probes included). Counted in REQ/ERR for honest stats, but say nothing about key health — they neither feed nor reset the breaker.">other 4xx count-only</span>
<span class="chip chip-yellow" title="Empty-body / throttle-phrased 403 (volume gating, not bad auth). Parks the key in a short cooldown (60s fallback, honors Retry-After) with NO quota signal, and fails over to the next key within the SAME request. Genuine auth 403s stay count-only.">throttle-403 → short cooldown + failover</span>
<span class="chip chip-muted" title="400/401/404 and genuine auth 403s (bad key, revoked, quota wording). Counted in REQ/ERR for honest stats, but say nothing about key health — they neither feed nor reset the breaker.">other 4xx count-only</span>
<span class="chip chip-muted" title="Fetch threw or the client disconnected (statusCode 0: connect timeouts, aborts, hung-upstream kills). Counted as an error, but never trips — a cancelled turn must not exile a healthy key.">transport errors never trip</span>
<span class="chip chip-muted" title="DNS down / no route / Wi-Fi off: the request never left the machine. Counted in REQ/ERR for honesty, but nothing else burns — no breaker feed, no failover cycling. The client gets HTTP 503 'Local network unreachable' instead of 'All API keys failed'.">local outage never burns</span>
</div>
Expand Down
18 changes: 11 additions & 7 deletions src/proxy/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -558,13 +558,17 @@ export class ProxyServer {
if (!repeatedServerError) {
this.keyManager.markError(key.id)
}
this.keyManager.recordRequest(key.id, {
statusCode: upstreamRes.status,
durationMs: duration,
model: prepared.model,
sessionId: upstreamSessionId ?? sessionKey ?? null,
successful: false,
})
if (attempt < maxAttempts - 1) {
// Counted here; on the last attempt the tail recordRequest
// below counts the verbatim 5xx once (no double-count).
this.keyManager.recordRequest(key.id, {
statusCode: upstreamRes.status,
durationMs: duration,
model: prepared.model,
sessionId: upstreamSessionId ?? sessionKey ?? null,
successful: false,
})
}
attemptedKeyIds.add(key.id)

if (circuitState === CircuitState.OPEN) {
Expand Down
Loading