在项目实际运行过程中,如果只有单机器,不考虑红黑发布等应用,代码更新迭代重新打包后,必须考虑平滑重启的问题。

平常开发过程中,都是直接粗暴的使用 CTRL+C 进行手动重启,这明显不能直接应用到生产环境中,这会导致服务中断。

这时可以使用 github.com/fvbock/endless ,他可以通过接收信号,处理完请求后再进行优雅重启。

https://github.com/fvbock/endless

# 安装
go get github.com/fvbock/endless

代码示例,配合使用Gin

package main

import (
    "net/http"
    "time"

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

func main() {
    r := gin.Default()
    r.GET("/get", func(c *gin.Context) {
        time.Sleep(time.Second * 5)
        c.JSON(http.StatusOK, gin.H{
            "hi": "23334",
        })
    })
    endless.ListenAndServe(":8001", r)
}

加入 time.Sleep() 是为了直观的体现出平滑重启的能力, 重启过程中不会中断服务, 请求会正常被处理。

go build 出程序后, 运行, 访问 localhost:8001/get , 等待5秒会返回JSON。

{"hi":"23334"}

直接修改程序中的 23334233345 , 重新 go build 打包。 使用 ps 找出上一个运行程序的PID,
先再次访问 localhost:8001/get , 然后命令行中操作重启

sudo kill -SIGHUP xxx

最后API中会返回

{"hi":"23334"}

再次访问 localhost:8001/get 后, 则会返回出最新改动

{"hi":"233345"}

重启过程中, 程序也会返回出相关信息

2021/11/26 17:13:01 
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /get                      --> main.main.func1 (3 handlers)

2021/11/26 17:13:01 18580 :8001
2021/11/26 17:13:01 18509 Received SIGTERM.
2021/11/26 17:13:01 18509 Waiting for connections to finish...
2021/11/26 17:13:01 18509 [::]:8001 Listener closed.
[GIN] 2021/11/26 - 17:13:04 | 200 |    5.0052797s |             ::1 | GET      "/get"
2021/11/26 17:13:04 18509 Serve() returning...
[GIN] 2021/11/26 - 17:13:14 | 200 |  5.005136313s |             ::1 | GET      "/get"

github.com/fvbock/endless 本身还支持其他信号,具体使用可以看文档,这里只简单介绍平滑重启的应用。