fix(proxy): detect stalled upstream websockets - #1579
Conversation
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # app/core/clients/proxy_websocket.py # app/modules/proxy/_service/http_bridge/upstream_events.py # app/modules/proxy/_service/websocket/mixin.py # tests/unit/test_proxy_http_bridge.py
|
Reviewed watchdog lifecycle and settlement ownership. Transport side is sound: no custom watcher task, both watchdogs are library-managed, and the direct-WS send/receive settlement claim in One settlement gap in the bridge reader blocks merge: P1 — P3 — classification is pinned to library-internal strings ( P3 — residual false-positive note, no change requested: both libraries stop processing pongs while transport reading is paused under recv backpressure, so a relay stalled >~ping_interval+timeout on downstream writes can kill a healthy upstream. Bounded by the same 120s downstream idle budget and the failure is account-neutral + retryable; the ops.md monitoring note covers it. Heads-up: this rewrites the same settlement/admission-waiter region as #1594 and the reservation paths #1536 touches — whichever lands second will need a careful rebase. #1558 (finalizer settlement ordering) is merging ahead in this same territory; expect a rebase over its websocket/mixin.py finalizer changes. |
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Addressed in For the P1 settlement gap:
For the P3 library-shape coverage:
The backpressure false-positive note remains unchanged as requested; the existing account-neutral/retryable behavior and ops monitoring note still bound and document it. Local verification after the #1558 merge:
GitHub CI for |
Summary
Detect silent upstream Responses WebSockets after a network/VPN transition and terminate affected conversations promptly instead of leaving them frozen until the container restarts.
This is a focused follow-up to #1234. That PR made observed host-network failures recoverable and account-neutral; this closes the remaining gap where an already-open WebSocket can become half-open without producing a read or write error.
Type of change
fix:— bug fix (no behavior change beyond the bug)Linked issue: None — reported directly; no matching issue was found.
OpenSpec
Change directory:
openspec/changes/archive/2026-08-04-recover-responses-websocket-liveness/Changes
heartbeatfor routed sockets and websocketsping_timeoutfor direct sockets. No new setting or background watcher is introduced.upstream_websocket_liveness_timeout, including aiohttp's stored heartbeat exception and websockets' acknowledged send-first 1011 close shape.response.create, settle every pending reservation/request exactly once, and retire the dead upstream generation.Simplicity
proxy_downstream_websocket_idle_timeout_secondsvalue is reused..env.example/ dashboard nav remain unchanged and within budget.Test plan
Passed locally:
Three serial local Codex review rounds were completed. Five P1 findings across the rounds were fixed and covered by regressions: stored aiohttp heartbeat exceptions, acknowledged direct close handshakes, bridge double settlement, bridge sibling settlement, and direct send/receive settlement ownership.
Screenshots / output
No dashboard-visible change. On upstream watchdog expiry, unsequenced requests receive a
response.failedevent with codeupstream_websocket_liveness_timeout; sequenced streams close with WebSocket code 1011 after settlement.Checklist