sighup 不能仅靠 signal.notify 简单处理,因其语义是重载而非退出;必须显式注册并用 switch 区分:sigterm/sigint 触发 shutdown,sighup 执行 reloadconfig 等轻量操作,严禁退出或 panic,确保幂等且不中断连接。

为什么 SIGHUP 不能只靠 signal.Notify 简单处理
很多服务部署在 systemd 或容器中,收到 SIGHUP 时默认行为是重启或重载配置,但 Go 程序若没显式注册该信号,系统就会按默认方式终止进程——这和没监听 SIGTERM 一样危险。更关键的是:SIGHUP 在某些场景(如 SSH 会话断开、systemd reload)下会高频触发,而它**不表示退出**,而是要求“重载”或“保持运行”,直接 shutdown HTTP server 就错了。
如何区分 SIGHUP 和 SIGTERM 的语义并分别响应
同一套信号通道不能混用处理逻辑。必须在 select 分支里判断具体信号类型,否则 SIGHUP 被当成退出信号,服务就意外挂了。
-
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)—— 注册时必须显式包含SIGHUP - 接收后用
switch sig分支:对SIGINT/SIGTERM执行 shutdown 流程;对SIGHUP则调用reloadConfig()或刷新日志句柄等轻量操作 - 避免在
SIGHUP处理中调用srv.Shutdown()或关闭 listener,它不该中断当前连接
systemd 场景下 SIGHUP 的特殊行为与适配
systemd 默认把 systemctl reload 映射为 SIGHUP,但它可能伴随 Restart=on-failure 策略误判——如果程序在 SIGHUP 处理中 panic 或 exit(0),systemd 会认为进程崩溃并重启。所以:
-
SIGHUP处理函数内严禁调用os.Exit()或引发 panic - 所有重载逻辑必须是幂等的:重复收到
SIGHUP不能导致配置叠加或连接泄漏 - 建议加日志前缀,比如
log.Printf("SIGHUP received, reloading config..."),方便和SIGTERM日志区分
goroutine 中监听 SIGHUP 需要额外注意什么
如果你把信号 channel 传给某个长期运行的 goroutine(比如配置监听器),它必须能单独响应 SIGHUP,且不能干扰主流程的退出控制流。
- 不要复用主 goroutine 的
donechannel 去响应SIGHUP—— 它只该用于终止 - 推荐为重载逻辑单独建一个
reloadCh := make(chan struct{}, 1),SIGHUP到来时select中发一次reloadCh - worker goroutine 用
select同时监听ctx.Done()(用于整体退出)和reloadCh(用于局部重载),两者互不阻塞
真正麻烦的不是捕获信号,而是让 SIGHUP 不被当成“我要死了”来处理——它本质是“请活久一点,顺便换个皮肤”。混淆这个语义,轻则配置失效,重则服务反复闪退。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











