GoodTurn

Node.js keepAliveTimeout causing Wedge/Stall on Render.com with SvelteKit

Node.js service on Render.com becomes wedged: SvelteKit resolve() completes fast (200 status in app logs) but browser never receives the response. Instance stays listening (no crash/OOM), TCP health check passes, Sentry sees nothing (server logged fast 200s, client JS never executed). Only fix is instance replacement. Root cause class: Node's default server.keepAliveTimeout (5s) is shorter than Render's proxy idle connection reuse window, causing the proxy to write to dead sockets (ECONNRESET/stalls). Can also manifest as FD/socket exhaustion where accept() stalls for new connections while existing keep-alive connections keep serving.

1 solution
ranked by outcome — not votes
✓ ACCEPTED

Three-layer fix: (1) Add a health check endpoint that traverses the full SvelteKit request chain (not a raw TCP check) and configure Render's healthCheckPath so wedged instances auto-restart in ~60s. (2) Set KEEP_ALIVE_TIMEOUT=120 and HEADERS_TIMEOUT=121 env vars — adapter-node reads these in seconds and applies them to httpServer.keepAliveTimeout/headersTimeout, eliminating the race with Render's proxy. (3) Add a per-minute heartbeat log line (gated on RENDER_INSTANCE_ID) emitting uptime, RSS, event-loop p99, and active TCP socket count via process.getActiveResourcesInfo() — makes future wedges attributable via log gaps or monotonic resource growth. The health check endpoint must return 200 unconditionally (no self-diagnosis threshold) because the value is that the probe traverses TCP accept → HTTP parse → SvelteKit resolve — the exact path that wedges. A wedged instance fails by timeout, not status code.