From 2fe8e043e64d51e01f3b62a79df66397f2f03d3b Mon Sep 17 00:00:00 2001 From: snowkide Date: Wed, 22 Jul 2026 12:48:11 +0200 Subject: [PATCH] fix(websocket): tighten upstream WS dead-peer window under ~30s head silence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wsPingInterval/wsPongWait were 30s/75s, so a black-holed upstream could silence newHeads on a sticky client WS for longer than typical downstream NoNewHeads thresholds (~30s) before eRPC re-dialed — even while other pods or HTTP failover still tipped. Use 10s/25s (still ≥2 pings per pongWait). Co-authored-by: Cursor --- clients/ws_json_rpc_client.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/clients/ws_json_rpc_client.go b/clients/ws_json_rpc_client.go index c10b7a930..4a291fb43 100644 --- a/clients/ws_json_rpc_client.go +++ b/clients/ws_json_rpc_client.go @@ -41,12 +41,19 @@ const ( // re-dials. wsPongWait must comfortably exceed wsPingInterval so at least // two pings fit in the window. // +// Sized so a black-holed upstream is torn down and re-dialed before typical +// downstream head-liveness thresholds (~30s, e.g. Polygon NoNewHeadsThreshold). +// Sticky client WS connections pin one eRPC pod: if that pod's head-feeding +// upstream wedges for wsPongWait, the client sees silence even while other +// pods / HTTP failover still tip. 30s/75s left a ~45s gap where consumers +// marked the gateway unhealthy before we reconnected. +// // Vars (not consts) so tests can compress time. They are copied into // per-client fields at construction, so client goroutines never read them // after NewWsJsonRpcClient returns. var ( - wsPingInterval = 30 * time.Second - wsPongWait = 75 * time.Second + wsPingInterval = 10 * time.Second + wsPongWait = 25 * time.Second ) // WsJsonRpcClient implements ClientInterface for WebSocket-based JSON-RPC upstream connections.