mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
5e5fe288d8
Every `docker stop` of a TREK instance with a browser attached exited 137, exactly ten seconds after the stop. `http.Server.close()` stops new connections and then waits for the open ones to end by themselves — and a WebSocket never does. TREK holds one per open tab, so the close callback never ran. `closeDb()` and `process.exit(0)` lived inside that callback, which left the only remaining exit a fallback timer set to 10000ms: exactly when Docker sends SIGKILL. Docker starts counting when it sends the signal and Node only once the handler is dispatched, so that timer started strictly later and could never win. It was unreachable code in every default deployment. Waiting for Nest was not an option either: `WsAdapter.close()` is the one place that terminates clients, and Nest reaches it only after every onModuleDestroy hook has resolved — including the plugin supervisor's SIGTERM grace for its forked children. The sockets holding the server open would be hostage to the slowest hook in the container. So the sockets are now released deliberately: ws clients get 1001 "going away", idle keep-alive sockets are dropped at once, and anything still attached after a 2s drain is destroyed. Nest is closed alongside that, the database is closed on both exit paths rather than only the unreachable one, and the fallback fires at 5s — inside Docker's grace, so a forced exit is still ours. The sequence moved into src/shutdown.ts behind injected dependencies. It was untestable by construction before, which is part of why this went unnoticed; it now has nine tests, including the signal that beats the bootstrap. Closes #2193 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S5VwmiBQ9sPCJwfmpv64r3