go程序需显式监听sigint和sigterm,用signal.notify(sigch, syscall.sigint, syscall.sigterm)配大小为1的chan os.signal,且须在业务启动前注册,否则信号丢失。

Go 程序不显式监听 SIGTERM 和 SIGINT,进程收到信号后会直接终止,所有 defer、清理逻辑、HTTP 响应刷盘全被跳过——这不是“没做好”,而是根本没启动信号处理链。
signal.Notify 必须传具体信号且配带缓冲 channel
写 signal.Notify(sigCh) 或只传 os.Interrupt 是常见错误。前者默认只监听 SIGINT 和 SIGQUIT,后者在 Linux 上等价于 SIGINT,完全漏掉 SIGTERM(Kubernetes、systemd、kill -15 全靠它)。
- 正确写法:
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) -
sigCh必须是chan os.Signal类型,不能是chan int或chan string,否则signal.Notify静默失败 - 缓冲大小设为 1 即可:
make(chan os.Signal, 1);设更大(如 10)掩盖设计缺陷,且无法解决“第二次信号到来时主 goroutine 还没读完”的本质问题 - Windows 下
SIGUSR1/SIGUSR2不可用,硬编码会导致编译失败,需加// +build !windows约束
监听必须在业务启动前完成,且要持续读取 channel
信号可能在 signal.Notify 调用前就已到达(比如容器启动快、宿主立刻发 SIGTERM),内核不会重试投递,未注册即丢失。
- 监听注册必须放在
http.ListenAndServe、长期for循环或消息消费 goroutine 启动之前 - 不能只
sig := 一次就退出 goroutine;必须用 <code>for { sig := 持续消费,否则第二次信号写入时缓冲区满,Go 运行时直接丢弃,无任何日志或 panic - 别把信号接收和清理逻辑写在同一 goroutine 里——清理耗时,会阻塞后续信号接收;应仅做通知,让主逻辑或独立 goroutine 处理 shutdown
优雅退出 ≠ 关掉 listener,shutdown 必须配 context 超时
http.Server.Close() 是危险操作:它立刻关闭 listener 并 reset 所有活跃连接,客户端看到 connection reset by peer,上传中断、WebSocket 断连全算你头上。
- 唯一正确路径:
srv.Shutdown(ctx),且ctx必须带超时,例如ctx, cancel := context.WithTimeout(context.Background(), 25*time.Second) - 超时值建议比 K8s 的
terminationGracePeriodSeconds小 5 秒,留出系统级清理余量 -
srv.Shutdown返回http.ErrServerClosed是正常退出标志,不是错误,需忽略 - handler 内部必须检查
req.Context().Done(),否则Shutdown会无限等待那些没响应 cancel 的请求
goroutine 泄漏和外部依赖必须统一受 context 控制
只关 HTTP server 不够。后台 time.Ticker、DB 查询、HTTP client 调用若没监听 ctx.Done(),它们会继续跑,进程卡死不退出。
- 所有长期 goroutine 启动时必须接收同一个
context.Context,并在select中监听ctx.Done() - DB 查询必须用
db.QueryContext(ctx, ...),HTTP client 必须传ctx,否则这些底层阻塞点会拖垮整个 shutdown 流程 -
db.Close()不响应 context,需单独调用;更安全做法是先db.SetMaxOpenConns(1)+db.PingContext(ctx),再db.Close() - 收到信号后不要调
os.Exit(0),它跳过所有 defer 和 runtime 清理;应让各组件主动退出,主 goroutine 等待关键资源关闭完成
真正容易被忽略的,是信号本身只是个通知开关——它不执行任何清理,也不保证其他 goroutine 会响应。从 signal.Notify 到资源释放完毕,中间每一步都得手动串联,漏一环,进程就僵在那儿。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











