Monorepo for Aesthetic.Computer aesthetic.computer

feat: graceful shutdown for lith — drain in-flight requests on restart

server.mjs catches SIGTERM/SIGINT, stops accepting new connections,
and waits up to 10s for in-flight requests to finish before exiting.
lith.service gets TimeoutStopSec=15 to match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+26 -2
+2
lith/lith.service
··· 10 10 ExecStart=/usr/bin/node server.mjs 11 11 Restart=on-failure 12 12 RestartSec=5 13 + TimeoutStopSec=15 14 + KillSignal=SIGTERM 13 15 StandardOutput=journal 14 16 StandardError=journal 15 17
+24 -2
lith/server.mjs
··· 608 608 }); 609 609 610 610 // --- Start server --- 611 + let server; 611 612 if (DEV && HAS_SSL) { 612 613 const opts = { 613 614 cert: readFileSync(SSL_CERT), 614 615 key: readFileSync(SSL_KEY), 615 616 }; 616 - createHttpsServer(opts, app).listen(PORT, () => { 617 + server = createHttpsServer(opts, app).listen(PORT, () => { 617 618 console.log(`lith listening on https://localhost:${PORT}`); 618 619 }); 619 620 } else { 620 - createHttpServer(app).listen(PORT, () => { 621 + server = createHttpServer(app).listen(PORT, () => { 621 622 console.log(`lith listening on http://localhost:${PORT}`); 622 623 }); 623 624 } 625 + 626 + // --- Graceful shutdown --- 627 + // On SIGTERM (sent by systemctl restart), stop accepting new connections 628 + // and wait for in-flight requests to finish before exiting. 629 + const DRAIN_TIMEOUT = 10_000; // 10s max wait 630 + 631 + function gracefulShutdown(signal) { 632 + console.log(`[lith] ${signal} received, draining connections...`); 633 + server.close(() => { 634 + console.log("[lith] all connections drained, exiting"); 635 + process.exit(0); 636 + }); 637 + // Force exit if connections don't drain in time 638 + setTimeout(() => { 639 + console.warn("[lith] drain timeout, forcing exit"); 640 + process.exit(1); 641 + }, DRAIN_TIMEOUT).unref(); 642 + } 643 + 644 + process.on("SIGTERM", () => gracefulShutdown("SIGTERM")); 645 + process.on("SIGINT", () => gracefulShutdown("SIGINT"));