router.run() 无法响应 sigint/sigterm 因其内部直接调用阻塞式 http.listenandserve() 且不暴露 *http.server 实例,导致无法调用 shutdown();必须监听 sigint、sigterm、sigquit 三信号;shutdown 超时建议电商接口设 5s、后台任务设 15s,并配 read/writetimeout;定时器、数据库事务、消息消费等 goroutine 若未响应 ctx.done() 会使进程卡在 shutdown() 后。

为什么 router.Run() 无法响应 SIGINT/SIGTERM
因为 router.Run() 内部直接调用阻塞式 http.ListenAndServe(),不暴露 *http.Server 实例,你根本拿不到句柄去调 Shutdown()。按 Ctrl+C 或收到 SIGTERM 时,进程直接退出,正在执行的数据库事务、文件写入、甚至刚读到一半的 HTTP body 都被硬中断。
必须监听哪些信号才能覆盖真实场景
生产环境里,SIGKILL(kill -9)无法捕获,也不该尝试;但以下三个必须全接住:
-
SIGINT:本地调试按 Ctrl+C 触发 -
SIGTERM:Kuberneteskubectl delete pod、systemdsystemctl stop默认发的信号 -
SIGQUIT:某些容器平台或旧版 systemd 会发它,漏掉会导致“看起来没关掉”
别加 SIGHUP 或其他无关信号——它不参与停机流程,反而可能干扰逻辑。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
shutdown context 超时设多少才不卡死也不丢请求
超时不是安全兜底值,而是业务容忍窗口。设太短(如 1s),会把正常慢请求(上传、支付回调、长轮询)直接掐断;设太长(如 30s),滚动更新时拖慢整个发布节奏,且掩盖了 goroutine 泄漏问题。
- 电商类接口建议从
5 * time.Second起步 - 后台任务或文件服务可放宽至
15 * time.Second - 必须配合
srv.ReadTimeout和srv.WriteTimeout(如都设为15 * time.Second),否则慢客户端会让连接 hang 住,Shutdown()永远等不到它结束
哪些 goroutine 容易让进程卡在 Shutdown() 后不退出
http.Server.Shutdown() 只管 HTTP 连接层,对你的业务 goroutine 完全无感。以下几类若没显式响应 ctx.Done(),main 就会永远 hang 住:
- 定时器:
time.AfterFunc(10*time.Second, ...)不受 context 控制,应改用time.NewTimer().Stop()或 select +ctx.Done() - 数据库事务:
GORM的db.Close()不等待未提交事务,需提前用tx.Commit(ctx)或tx.Rollback(ctx) - 消息消费:
go func() { for range ch { ... } }()必须加select { case 判断退出 - Redis/HTTP 客户端未调
client.Close(),底层连接池不会自动释放
验证是否真优雅?启动后立刻 curl -s http://localhost:8080/slow && sleep 0.1 && kill -TERM $(pidof yourapp),再看进程是否消失、日志是否有 Server closed under request —— 卡着不动,八成是某个 goroutine 没听 cancel。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










