From 3a28c4b1b7177ae2567f6b5b8af2f7f7284bf557 Mon Sep 17 00:00:00 2001 From: Jaret Burkett Date: Sat, 8 Aug 2026 20:27:01 -0600 Subject: [PATCH] Keep alive cron server to prevent failed connections --- ui/cron/fileServer.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ui/cron/fileServer.ts b/ui/cron/fileServer.ts index 0251547..f115937 100644 --- a/ui/cron/fileServer.ts +++ b/ui/cron/fileServer.ts @@ -288,6 +288,22 @@ function proxy(req: http.IncomingMessage, res: http.ServerResponse, upstreamPort setTimeout(() => proxy(req, res, upstreamPort, attempt + 1), 250); return; } + // Keep-alive reuse race: Next.js closes pooled sockets after 5s idle, and + // the UI polls on ~5s intervals, so a reused socket can die the instant we + // write to it (ECONNRESET/EPIPE). No response bytes exist yet, so retrying + // immediately is safe; each retry drains one stale socket from the pool + // until a live or fresh connection is used. + if ( + bodyless && + upstreamReq.reusedSocket && + (err.code === 'ECONNRESET' || err.code === 'EPIPE') && + !res.headersSent && + !res.destroyed && + attempt < 120 + ) { + proxy(req, res, upstreamPort, attempt + 1); + return; + } if (res.destroyed) return; if (!res.headersSent) res.writeHead(502); res.end('UI server unavailable');