go服务需监听sigint/sigterm信号,调用http.server.shutdown()并让所有goroutine响应ctx.done(),三者缺一不可;shutdown()须配context.withtimeout()避免卡住,且不可忽略清理逻辑。

Go 服务收到 SIGINT 或 SIGTERM 后直接退出,不是“退出”,是“猝死”:请求中断、日志截断、数据库事务回滚不完整、临时文件残留。必须手动监听信号 + 调用 http.Server.Shutdown() + 所有 goroutine 响应 ctx.Done(),三者缺一不可。
为什么 http.ListenAndServe() 不能直接退出
它本身是阻塞调用,但完全不响应系统信号。Ctrl+C 或容器发来的 SIGTERM 会直接终止进程,defer 不执行、连接重置、db.Close() 被跳过、最后一行日志写一半就丢。
-
http.ListenAndServe()返回的http.ErrServerClosed是正常关闭信号,不是错误,必须忽略 - 别在
go srv.ListenAndServe()后没做任何信号处理就让 main 函数结束——主 goroutine 一退,所有后台 goroutine 立刻被杀 - 用
os.Exit(0)或log.Fatal()替代 shutdown,等于主动放弃所有正在运行的请求和清理逻辑
怎么用 srv.Shutdown() 才不卡住
Shutdown() 只是发起通知,它不等待连接完成,也不设超时——你得自己套一层 context.WithTimeout(),且超时时间必须略大于你最长请求耗时(比如上传接口设 15 秒,别设 5 秒)。
- 必须传带超时的 context:
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second);context.Background()会导致永久阻塞 - 调用前确保
srv.Listener已关闭(Shutdown()内部会做),新连接进不来 - 错误只忽略
http.ErrServerClosed,其他如超时、网络错误该log.Printf()就log.Printf() - 别在
srv.Shutdown(ctx)后立刻return或os.Exit()——它返回 ≠ 所有连接已结束,但已进入清理阶段,后续要等 goroutine 退出
后台 goroutine 怎么同步退出
所有长期运行的 goroutine(消息消费者、定时任务、健康检查)都必须监听同一个 ctx.Done(),不能靠 time.Sleep() 或无条件 for {} 硬等。
- 用
select { case ,而不是 <code>if ctx.Err() != nil { return }——后者只查一次,错过取消信号 - 清理逻辑(如
db.Close()、redisPool.Close()、os.RemoveTemp())必须写在case 分支里,不能丢进 <code>defer - 多个服务共存(HTTP + gRPC + 消费者),用共享
context.WithCancel()驱动,配合sync.WaitGroup等全部 goroutine 退出;wg.Wait()放在 main 最后,别放defer
信号监听为什么收不到 SIGTERM
signal.Notify() 只注册监听,不阻塞;如果注册完没从 channel 读取,主 goroutine 直接退出,整个程序就结束了,根本来不及响应。
- 必须用带缓冲的 channel:
sigChan := make(chan os.Signal, 1),避免信号丢失 - 必须显式接收:
或 <code>for range sigChan,否则信号来了也白搭 - 别把信号监听和 server 启动放在两个独立 goroutine 里却不协调——容易出现 server 还没起来,信号就先到了
- 容器环境(Kubernetes)中,
SIGTERM通常比 readiness probe 下线快,所以 shutdown 流程越早启动越好,最好在go srv.ListenAndServe()前就注册信号
最容易被忽略的是 handler 里那些“看起来没问题”的阻塞操作:没传 ctx 的 db.QueryRow()、没设 timeout 的 http.Client.Do()、或裸写的 time.Sleep()——它们不会响应 ctx.Done(),会拖垮整个 shutdown 流程,导致超时强制退出。优雅退出不是加个 Shutdown() 就完事,而是整条调用链都要支持取消。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











