我正在尝试使用传递给我的类的父上下文来实现一种干净的方式来优雅地停止我的杜松子酒服务器。 这是我当前的代码
有没有更干净的方法来做到这一点?感觉像是很多样板代码并且不必要,例如使用无限循环来完成如此简单的任务。
func (instance *MyListener) Listen(ctx context.Context) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
engine := gin.Default()
engine.POST("/doStuff", func(c *gin.Context) {
instance.doStuff()
c.Status(200)
})
instance.httpSrv = &http.Server {
Addr: ":8080",
Handler: engine,
}
// Initializing the server in a goroutine so that
// it won't block the graceful shutdown handling below
go func() {
if err := instance.httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logging.Log.Error("Could not start listener", zap.Error(err))
}
}()
loop:
for {
select {
case <- ctx.Done():
break loop
default:
time.Sleep(1000)
}
}
ctx, cancel = context.WithTimeout(ctx, 2 * time.Second)
if err := instance.httpSrv.Shutdown(ctx); err != nil {
logging.Log.Error("Server forced to shutdown:", err)
}
return nil
}
这个:
loop:
for {
select {
case <- ctx.Done():
break loop
default:
time.Sleep(1000)
}
}
可以用这个代替:
<- ctx.Done()
而且它同样有效并且“更高效”。除此之外,您的解决方案看起来干净、清晰且正确。
func (instance *MyListener) Listen(ctx context.Context) error {
engine := gin.Default()
engine.POST("/doStuff", func(c *gin.Context) {
instance.doStuff()
c.Status(200)
})
instance.httpSrv = &http.Server {
Addr: ":8080",
Handler: engine,
}
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
go func() {
if err := instance.httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logging.Log.Error("Could not start listener", zap.Error(err))
}
}()
<-ctx.Done()
stop()
log.Printf("Gracefully shutting down the server...\nPress CTRL + C again to force")
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
if err := instance.httpSrv.Shutdown(ctx); err != nil {
logging.Log.Error("Server forced to shutdown:", err)
}
return nil
}
这样它会非常有趣:
首次尝试关闭服务器后,它将等待给定的超时时间来正常关闭,如果请求花费的时间超过超时时间,服务器将强制关闭。