本篇博客讲一讲gin 优雅关闭服务。
所谓的优雅关闭服务就是 在关闭服务时,服务不再监听新的请求,并且可以将之前的请求处理完毕。好了,先上代码
1、修改项目根目录main.go 代码,超时时间设置了10s,完整代码如下
package main
import (
"context"
"fmt"
"ginWeb/config"
"ginWeb/handler"
router2 "ginWeb/router"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
router := router2.InitRoutes(handler.NewApp())
srv := &http.Server{
Addr: fmt.Sprintf(":%s", config.Settings.App.Port),
Handler: router,
}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
return
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
fmt.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
fmt.Printf("shutdown.err =%v\n",err)
}
fmt.Println("Server exiting")
}
为了看到效果,业务代码 /handler/app.go,睡眠了5秒钟 完整代码如下
package handler
import (
log "ginWeb/common/logger"
"ginWeb/common/store"
"golang.org/x/net/context"
"time"
)
type UaaHandler interface {
Login(ctx context.Context, req *LoginReq, rsp *LoginRsp) error
}
type uaa struct {
db *store.DB
}
func newUaaHandler(db *store.DB) UaaHandler {
return &uaa{db}
}
type LoginReq struct{}
type LoginRsp struct {
Id int64 `json:"id"`
Name string `json:"name"`
}
func (u *uaa) Login(ctx context.Context, req *LoginReq, rsp *LoginRsp) error {
log.Error("===========login==========start", nil)
time.Sleep(time.Second * 5)
rsp.Id, rsp.Name = 123, "小明"
log.Error("===========login==========end", nil)
return nil
}
进行两个测试
1、先请求接口,然后立即关闭服务,请求正常返回
2、关闭服务,然后请求,报错 Connection refused
两个测试通过,说明代码可以实现优雅关闭服务
小结一下
上面 启动 服务是把 http的监听服务 放在一个groutine 里边,然后下面注册了 一个chanel 到信号通知里边,只监听 2 号信号(在 Linux 中,2 号信号通常指的是 SIGINT 信号。SIGINT 是程序终止信号,通常由用户在终端上按下 Ctrl+C 生成。当一个进程接收到 SIGINT 信号时,它会默认终止自己的执行。
) ,15 号信号(
在 Linux 中,15 号信号通常指的是 SIGTERM 信号。SIGTERM 是一种用于请求进程正常终止的信号。当一个进程接收到 SIGTERM 信号时,它应该进行清理工作并安全地退出。 与 SIGKILL 不同,SIGTERM 允许进程有机会在接收到信号后执行一些清理操作,然后自行退出。这使得 SIGTERM 更友好,适用于需要正常关闭的情况。
)服务没收到信号之前,会一直 阻塞在 读 channel 那块。当收到信号后,会调用 shutdown方法,该方法 首先会关闭 监听器(不再监听新的请求
),然后循环关闭 所有的空闲链接,直到 不存在active 链接,此时服务关闭完成。
注意看下上面 设置了一个超时时间,超时时间的取值可以参考自己项目的请求最大时间,否则超时时间到了会直接关闭服务,请求不一定会处理完毕。当然也可以不设置超时时间,这样 老的请求一定会处理完毕,但是可能出现 老的请求一直在阻塞导致 服务一直关闭不了。所以建议设置合理的超时时间
创作不易,喜欢的话请一键三连,转载请注明出处,侵权必究