GO服务如何优雅的退出、重启
==============
简介
—
在服务端开发的时候,往往都会有一些关于服务器关闭、服务器重启之类的问题出现。这里简单介绍了 go服务 收到signal信号之后的关闭、重启操作。
参考:
说明
go 中实现优雅的退出,主要使用了 os/signal
包,让程序能够接收到信号,并对信号执行一些操作。比如在linux下,也可以对一些信号进行捕捉,甚至改变信号所对应的行为。
退出部分的代码在退出
标题里,其它代码只是我的一个测试环境,可以忽略。
这里我使用的是gin框架,并在gin框架中引入了os/signal包,实现对信号的处理(只做了部分信号的处理)。
并且有些信号不能被捕获,最常见的就是 kill -9
强杀,具体请看下最常见的信号列表。
代码实现
func (p *router) Run(host, port string) {
//TODO 优化zap log日志,修改成自定义的zap 的logger
//err := p.engine.Run(host + ":" + port)
//if err != nil {
// //路由启动失败,终止程序
// panic(err)
//}
//下面所有代码(go1.8+)是为了优雅处理重启等动作
srv := &http.Server{
Addr: host + ":" + port,
Handler: p.engine,
ReadTimeout: constant.ReadTimeoutT * time.Second,
WriteTimeout: constant.WriteTimeoutT * time.Second,
}
go func() {
// 监听请求
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err)
}
}()
// 优雅Shutdown(或重启)服务
// 有一点需要注意的是:这里设置的重启/关闭条件是 收到kill信号,即程序意外终止
// 假如,我在这里用一个go携程,让它在2秒之后,panic程序,并且不进行recover恢复程序,那么panic会给进程发送一个os.Exit(2)(源码中可以看),
// 这个是会被认为 程序主动退出 ,而非被kill 也就是进程不会收到 kill信号,也就无法重启/关闭了 (虽然panic让程序崩溃了)
// 当注释掉下方go程中的defer的时候,程序直接panic,而不重启,反之则可以重启
//go func() {
// defer Recover()
//
// time.Sleep(2 * time.Second)
// panic("dangerous")
//}()
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt) // syscall.SIGKILL
<-quit
logger.Info("Shutdown Server...")
// 10秒后,关闭context-即服务器于10秒后重启,或关闭(gin中的Context,也就是说客户端发送的一次请求,如果在10秒内没处理完,那么这个ctx将会失效,即无法在服务器重启前,成功处理客户端的请求)
//TODO 设置一个context失效时间
ctx, cancel := context.WithTimeout(context.Background(), constant.ServerRestart*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
logger.Fatalf("Server Shutdown: ", err)
}
select {
case <-ctx.Done():
}
logger.Info("Server exiting...")
}
func Recover() {
if p := recover(); p != nil {
fmt.Println("p = ", p)
}
}
如下,捕捉到了ctrl+c对应的信号之后,执行了退出操作,重启服务的时候也可以执行退出操作。
原文链接: https://juejin.cn/post/7352075798068412442
文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17386.html