记录在 gin 框架中优雅退出的实现方式。
系统退出信号
信号(Signal)是 linux 中进程间通信的一种方式,当信号发送到某个进程中时,操作系统会中断该进程的正常流程,并进入相应的信号处理函数执行操作,完成后再回到中断的地方继续执行。
比如在中端中键入某些组合键会导致系统发送某些信号给该进程。
常见的信号有:
- SIGINT:中断信号,通常是键盘上的 Ctrl+C
- SIGTERM:终止信号,通常是 kill 命令
- SIGQUIT:退出信号,通常是键盘上的 Ctrl+\
- SIGKILL:强制终止信号,通常是 kill -9 命令
- SIGSTOP:停止信号,通常是 kill -STOP 命令
其中 SIGKILL
与 SIGSTOP
信号是无法被捕获的,即使注册了信号处理函数也不会执行。
go 中的信号接收与处理
go 中可以创建一个接收 os.Signal
类型的 channel
变量,然后调用 signal.Notify
函数注册想要拦截的系统信号,将接收到的信号转发到该 channel
变量中,然后在 channel
变量中读取信号即可。
gin 中的优雅退出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| var (
router = gin.Default()
server *http.Server
)
func Run() {
getRoutes()
server = &http.Server{
Addr: ":8080",
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
go func() {
// 服务连接
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal("listen: %s\n", log.Err(err))
}
}()
gracefulExit(server)
// router.Run(":8080")
}
func getRoutes() {
douyin := router.Group("/douyin")
addUserRoutes(douyin)
}
func gracefulExit(server *http.Server) {
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
sig := <-ch
log.Info("receive exit signal", log.Any("", sig))
now := time.Now()
cxt, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err := server.Shutdown(cxt)
if err != nil {
log.Error("server shutdown error", log.Err(err))
}
// 实际退出所耗费的时间
log.Info("------exited--------", log.Duration("duration:", time.Since(now)))
}
|