From 92ee1282145593960d3050aad055929b6d3d08dc Mon Sep 17 00:00:00 2001 From: Amit <3540115+amitdeshmukh@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:20:19 +0530 Subject: [PATCH] fix(serv): bound shutdown so Ctrl-C exits when SSE/keep-alive conns linger s.srv.Shutdown was called with context.Background(), so any in-flight HTTP connection (most commonly an MCP SSE stream) blocked shutdown forever. "shutdown complete" was also logged from RegisterOnShutdown, which fires asynchronously, so the log line printed even though the process never exited. Give Shutdown a 10s timeout, fall back to srv.Close() on timeout, and run closeFn/cache/db cleanup inline after Shutdown returns so the final log reflects reality. Co-Authored-By: Claude Opus 4.7 (1M context) --- serv/serv.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/serv/serv.go b/serv/serv.go index 5a8fc4e4..3a4a0569 100644 --- a/serv/serv.go +++ b/serv/serv.go @@ -72,14 +72,18 @@ func startHTTP(s1 *HttpService) { sigint := make(chan os.Signal, 1) signal.Notify(sigint, os.Interrupt) <-sigint + s.log.Info("shutdown signal received") - if err := s.srv.Shutdown(context.Background()); err != nil { - s.log.Warn("shutdown signal received") + // Bounded shutdown: don't wait forever on lingering connections + // (e.g. MCP SSE streams or idle keep-alives). + shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + if err := s.srv.Shutdown(shutdownCtx); err != nil { + s.log.Warnf("graceful shutdown timed out, forcing close: %s", err) + s.srv.Close() //nolint:errcheck } - close(idleConnsClosed) - }() - s.srv.RegisterOnShutdown(func() { if s.closeFn != nil { s.closeFn() } @@ -93,7 +97,8 @@ func startHTTP(s1 *HttpService) { } } s.log.Info("shutdown complete") - }) + close(idleConnsClosed) + }() ver := version // dep := s.conf.name