1. 首页
  2. 后端

GO服务如何优雅的退出、重启

  GO服务如何优雅的退出、重启

==============

简介

在服务端开发的时候,往往都会有一些关于服务器关闭、服务器重启之类的问题出现。这里简单介绍了 go服务 收到signal信号之后的关闭、重启操作。

参考:

优雅退出在Golang中的实现 (qq.com)

Go语言WEB框架(Gin)详解

说明

go 中实现优雅的退出,主要使用了 os/signal 包,让程序能够接收到信号,并对信号执行一些操作。比如在linux下,也可以对一些信号进行捕捉,甚至改变信号所对应的行为。

退出部分的代码在退出标题里,其它代码只是我的一个测试环境,可以忽略。

这里我使用的是gin框架,并在gin框架中引入了os/signal包,实现对信号的处理(只做了部分信号的处理)。

并且有些信号不能被捕获,最常见的就是 kill -9 强杀,具体请看下最常见的信号列表。

image.png

代码实现

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对应的信号之后,执行了退出操作,重启服务的时候也可以执行退出操作。

image.png

原文链接: https://juejin.cn/post/7352075798068412442

文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17386.html

QR code