From d1b0a3584f2c25ee3353c08c5e1f9c0e3453e52b Mon Sep 17 00:00:00 2001 From: Nicholas Spisak Date: Fri, 9 Jan 2026 14:40:03 -0500 Subject: [PATCH] fix(discord): add zombie connection detection with HELLO timeout Add 30-second timeout after WebSocket opens to detect when Discord never sends HELLO (zombie state). If isConnected stays false after timeout, forces a fresh connection instead of hanging indefinitely. Relates to #595 --- src/discord/monitor.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/discord/monitor.ts b/src/discord/monitor.ts index b3402cd44..ff2e46499 100644 --- a/src/discord/monitor.ts +++ b/src/discord/monitor.ts @@ -504,6 +504,27 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) { emitter: gatewayEmitter, runtime, }); + // Timeout to detect zombie connections where HELLO is never received. + const HELLO_TIMEOUT_MS = 30000; + let helloTimeoutId: ReturnType | undefined; + const onGatewayDebug = (msg: unknown) => { + const message = String(msg); + if (!message.includes("WebSocket connection opened")) return; + if (helloTimeoutId) clearTimeout(helloTimeoutId); + helloTimeoutId = setTimeout(() => { + if (!gateway?.isConnected) { + runtime.log?.( + danger( + `[discord] connection stalled: no HELLO received within ${HELLO_TIMEOUT_MS}ms, forcing reconnect`, + ), + ); + gateway?.disconnect(); + gateway?.connect(false); + } + helloTimeoutId = undefined; + }, HELLO_TIMEOUT_MS); + }; + gatewayEmitter?.on("debug", onGatewayDebug); try { await waitForDiscordGatewayStop({ gateway: gateway @@ -526,6 +547,9 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) { }); } finally { stopGatewayLogging(); + stopGatewayLogging(); + if (helloTimeoutId) clearTimeout(helloTimeoutId); + gatewayEmitter?.removeListener("debug", onGatewayDebug); } }