golang 实现优雅的关机和重启

优雅地关机

  优雅关机就是服务端关机命令发出后不是立即关机,而是等待当前还在处理的请求全部处理完毕后再退出程序,是一种对客户端友好的关机方式。而执行Ctrl+C关闭服务端时,会强制结束进程导致正在访问的请求出现问题。

 

golang实现优雅的关机

package main

import (
    "fmt"
    "net/http"
    "context"
    "log"
    "os"
    "os/signal"
    "time"


    "gin-blog/routers"
    "gin-blog/pkg/setting"
)

func main() {
    router := routers.InitRouter()

    s := &http.Server{
        Addr:           fmt.Sprintf(":%d", setting.HTTPPort),
        Handler:        router,
        ReadTimeout:    setting.ReadTimeout,
        WriteTimeout:   setting.WriteTimeout,
        MaxHeaderBytes: 1 << 20,
    }

    go func() {
        if err := s.ListenAndServe(); err != nil {
            log.Printf("Listen: %s\n", err)
        }
    }()
    
    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt)
    <- quit

    log.Println("Shutdown Server ...")

    ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
    defer cancel()
    if err := s.Shutdown(ctx); err != nil {
        log.Fatal("Server Shutdown:", err)
    }

    log.Println("Server exiting")
}

 

 

优雅地重启

 

   

优雅关机实现了,那么该如何实现优雅重启呢?

我们可以使用 fvbock/endless 来替换默认的 ListenAndServe启动服务来实现, 示例代码如下:

package main

import (
    "log"
    "net/http"
    "time"

    "github.com/fvbock/endless"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.GET("/", func(c *gin.Context) {
        time.Sleep(5 * time.Second)
        c.String(http.StatusOK, "hello gin!")
    })
    // 默认endless服务器会监听下列信号:
    // syscall.SIGHUP,syscall.SIGUSR1,syscall.SIGUSR2,syscall.SIGINT,syscall.SIGTERM和syscall.SIGTSTP
    // 接收到 SIGHUP 信号将触发`fork/restart` 实现优雅重启(kill -1 pid会发送SIGHUP信号)
    // 接收到 syscall.SIGINT或syscall.SIGTERM 信号将触发优雅关机
    // 接收到 SIGUSR2 信号将触发HammerTime
    // SIGUSR1 和 SIGTSTP 被用来触发一些用户自定义的hook函数
    if err := endless.ListenAndServe(":8080", router); err!=nil{
        log.Fatalf("listen: %s\n", err)
    }

    log.Println("Server exiting")
}

但是需要注意的是,此时程序的PID变化了,因为endless 是通过fork子进程处理新请求,待原进程处理完当前请求后再退出的方式实现优雅重启的。所以当你的项目是使用类似supervisor的软件管理进程时就不适用这种方式了。

 

posted @ 2021-07-26 14:59  pebblecome  阅读(881)  评论(0编辑  收藏  举报