我在《Go 标准库 net/http 如何实现优雅退出?》 一文中讲解了 net/http 实现的 HTTP Server 如何优雅退出,又在《深挖 Go 标准库 net/http 源码,来看看优雅退出到底是如何实现的?》一文讲解了优雅退出源码是如何实现的。
Gin 的优雅退出
但在工作中,我们开发 Go Web 程序时,往往不会直接使用 net/http 包,而是引入一个第三方库或框架。其中 Gin 作为 Go 生态中最为流行的 Web 库,我觉得有必要讲解一下在 Gin 中如何进行优雅退出。
不过,学习了 net/http 的优雅退出,实际上 Gin 框架的优雅退出是一样的,因为 Gin 只是一个路由库,提供 HTTP Server 能力的还是 net/http。
Gin 框架中的优雅退出示例代码如下:
package main
import (
"context"
"errors"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
router.GET("/sleep", func(c *gin.Context) {
duration, err := time.ParseDuration(c.Query("duration"))
if err != nil {
c.String(http.StatusBadRequest, err.Error())
return
}
time.Sleep(duration)
c.String(http.StatusOK, "Welcome Gin Server")
})
srv := &http.Server{
Addr: ":8000",
Handler: router,
}
go func() {
// 服务连接
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
// Error starting or closing listener:
log.Fatalf("HTTP server ListenAndServe: %v", err)
}
log.Println("Stopped serving new connections")
}()
// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
<-quit
log.Println("Shutdown Server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// We received an SIGINT/SIGTERM signal, shut down.
if err := srv.Shutdown(ctx); err != nil {
// Error from closing listeners, or context timeout:
log.Printf("HTTP server Shutdown: %v", err)
}
log.Println("HTTP server graceful shutdown completed")
}
可以发现,在 Gin 框架中实现优雅退出代码与我们在 net/http 包中的实现没什么不同。
只不过我们在实例化 http.Server 对象时,将 *gin.Engine 作为了 Handler 复制给 Handler 属性:
srv := &http.Server{
Addr: ":8000",
Handler: router,
}
执行示例程序测试优雅退出,得到如下输出:
$ go build -o main main.go && ./main
[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 /sleep --> main.main.func1 (3 handlers)
^C2024/08/22 09:23:36 Shutdown Server...
2024/08/22 09:23:36 Stopped serving new connections
[GIN] 2024/08/22 - 09:23:39 | 200 | 5.001282167s | 127.0.0.1 | GET "/sleep?duration=5s"
2024/08/22 09:23:39 HTTP server graceful shutdown completed
$ curl "http://localhost:8000/sleep?duration=5s"
Welcome Gin Server
这里同样在处理请求的过程中,按下 Ctrl + C,根据日志可以发现,Gin 示例代码中的优雅退出没有问题。
Gin 框架文档 也提到了在 Go 1.8 版本之前可以使用如下几个第三方库实现的优雅退出替代方案:
- manners:可以优雅关机的 Go Http 服务器。
- graceful:Graceful 是一个 Go 扩展包,可以优雅地关闭 http.Handler 服务器。
- grace:Go 服务器平滑重启和零停机时间部署。
当然我们使用的是 Go 1.8 以上版本,可以不需要这些库。因为 net/http 已经提供了原生的优雅退出方案,所以几乎用不到它们,感兴趣的可以自行研究下。
NOTE: 可以参阅 Gin 完整的 graceful-shutdown 示例。
联系我
- 公众号:Go编程世界
- 微信:jianghushinian
- 邮箱:jianghushinian007@outlook.com
- 博客:jianghushinian.cn