在golang当中,我们经常需要在服务器关闭的那一瞬间去做一些操作
比如:
// 优雅关闭和退出
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
这段代码的含义就是,创建一个监听系统信号的channel,在系统退出的时刻会向 quit 发送一个信号
这段代码主要监听两个信号,也是业界中常用的两个信号
| 信号 | 来源 | 程序是否可捕获 | 常见用途 |
|---|---|---|---|
| SIGINT | Ctrl+C | 可以 | 本地手动停止 |
| SIGTERM | kill / 容器停止 / k8s pod 杀死 | 可以 | 优雅关闭 |
| SIGKILL | kill -9 | 不可以 | 强制杀死 |
不过需要注意的是,主要针对人为的Ctrl + C、进程被kill、docker容器被kill以及k8s pod被kill的信号
vscode中的dlv debug, 直接 detach 或调用 ptrace 终止进程。
真实结构是:
dlv (调试器进程) └── 被调试的 Go 进程
而且:
暂停杀的是dlv调试程序,go进程无法监听到信号就被杀死了
使用air的默认配置是无法触发优雅退出的
实际结构是:
air 进程 └── 你的 Go 程序
和 dlv 不同的是:
优雅退出应该这样做
[build]
kill_delay = "5s"
send_interrupt = true
在build选项后修改这两个配置项,send_interrupt指的是给子进程发Ctrl + C的退出信号,并预留5s的时间给子进程。
func (a *App) Start() {
// 优雅关闭和退出
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
a.engine.Run(fmt.Sprintf(":%d", conf.GetGlobalConfig().Server.Port))
}()
<-quit
log.Println("exit wschat")
}