使用时间窗口的目的
使正在运行的服务停止接收新请求,并在最终关闭之前完成正在进行的请求。为了实现上述目的,可以创建一个带有超时的上下文,使用channel监听中断信号,为服务其关闭提供一个时间窗口。
代码实现
初始化通道
signalChan = make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
func gracefulShutdown() {
select {
case msg := <-signalChan:
switch msg {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM:
global.Log.Info("API Server Shutdown......")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
global.Log.Error(fmt.Sprintf("API Server Shutdown Error: %+v", err))
}
}
os.Exit(0)
}
}
创建带时间窗口的上下文
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
关闭服务
if err := server.Shutdown(ctx); err != nil {
global.Log.Error(fmt.Sprintf("API Server Shutdown Error: %+v", err))
}
实现监听通道
select {
case msg := <-signalChan:
switch msg {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM:
global.Log.Info("API Server Shutdown......")
}
os.Exit(0)
}
整合代码
func main() {
flag.Parse()
config.Init(env)
signalChan = make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
// 监听中止信号
go gracefulShutdown()
app, cancel, err := initServer()
defer cancel()
if err != nil {
panic(err)
}
server = app.Start()
global.Log.Info(fmt.Sprintf("API Server start at %s", server.Addr))
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
global.Log.Fatal(fmt.Sprintf("start gamefi openapi server failed, err: %s", err))
}
}
func gracefulShutdown() {
select {
case msg := <-signalChan:
switch msg {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM:
global.Log.Info("API Server Shutdown......")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
global.Log.Error(fmt.Sprintf("API Server Shutdown Error: %+v", err))
}
}
os.Exit(0)
}
}