Go程序如何优雅退出
目录
背景
优雅的退出 Go 程序:关闭数据库连接、关闭 redis 连接、等待协程执行、清理数据等等…
实现
通过监听程序信号 ctrl + c 优雅退出,代码实现如下:
package main
import (
"log"
"os"
"os/signal"
"syscall"
)
func main() {
//TODO 执行业务代码
//监听退出序号
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
log.Println(sig)
done <- true
}()
log.Println("Server Start Awaiting Signal")
<-done
// 执行清理操作
cleanup()
log.Println("Exiting")
}
原理
操作系统信号机制
┌───────────────┐ ┌───────────────┐
│ 用户按下Ctrl+C │─────>│ 生成SIGINT信号 │
└───────────────┘ └───────────────┘
↓
┌───────────────────────────────┐
│ Go程序通过signal.Notify捕获信号 │
└───────────────────────────────┘
信号名称 | 默认行为 | 触发场景 | Go可否捕获 |
---|---|---|---|
SIGINT | 终止进程 | Ctrl+C / kill -2 | ✅ |
SIGTERM | 终止进程 | kill默认 / 容器停止 | ✅ |
SIGKILL | 强制终止 | kill -9 / 系统OOM | ❌ |
SIGHUP | 终止进程 | 终端断开 / 守护进程重载配置 | ✅ |
SIGQUIT | 核心转储 | Ctrl+\ | ✅ |
常见问题
1. 为什么有时候捕获不到?
操作系统强制终止进程 / 内存溢出被容器强制终止,不经过应用程序处理流程