pi-model-auto-router: stalled stream (90s no events) is treated as fatal, should failover like transient errors #10
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
weisanju/pi-plugins#10
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
When a target provider accepts the connection but stops sending SSE events for 90s, the stall watchdog treats it as a fatal error: it logs
fatal, pushes the error to the caller, and aborts. It never attempts failover to the other targets in the route, even though a stalled upstream is transient in nature (same root cause as 503 BAD_UPSTREAM timeouts).Environment
Reproduction
Route config with multiple targets (e.g.
cache-first):event: fatal, the request fails — no failover to the other targets.In the same session a minute later, the same target returned
503 {"cause":"Post \"http://kimi-k3.jd.com/v1/chat/completions\": net/http: timeout awaiting response headers"}— that one was classified transient and correctly failed over to the next target.Observed code path (dist/index.js, v0.3.1)
In the watchdog callback (~line 800):
Note the error event path (
if (event.type === "error" && !committed)) goes throughclassifyFailure()and the failover logic, but the stall path bypasses it entirely and is hardcoded to fatal.Expected behavior
A stalled stream should be treated like a transient failure (upstream hang / timeout):
stallClass: "transient" | "fatal").Why it matters
With a single hung upstream, the whole request fails even when healthy backups are configured — the failover list is effectively useless against the "connected but silent" failure mode, which is a very common one for self-hosted/LLM-gateway backends.