什么是优雅关机
http-server运行过程中,若过程被敞开,那么正在解决的申请可能只被解决了一半就进行了,可能会产生数据的不统一。
优雅关机是指:
- 首先,进行接管新申请;
- 而后,期待队列中的申请被处理完毕;
- 最初,应用程序退出;
net/http如何实现优雅关机
net/http原生反对优雅关机。
首先,在goroutine中启动http-server:
srv := &http.Server{ Addr: ":8090", Handler: r,}go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatal("listen: ", err) } else { log.Println("ListenAndServe break") }}()
而后,在main中监听关机信号:
- SIGTERM: kill的默认信号;
- SIGINT:kill -2,个别是Ctrl+C的退出;
- SIGKILL:kill -9,捕捉不到;
quit := make(chan os.Signal, 1)signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)<- quit
最初,监听到关机信号后,执行优雅关机:
- 调用srv.Shutdown()执行优雅关机;
- 默认期待所有队列中的申请处理完毕后,才返回;
- 传入timeoutContext,减少超时工夫,超时工夫到后返回;
ctx, cancel := context.WithTimeout(context.TODO(), 20*time.Second)defer cancel()if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server shutdown: ", err)}
net/http优雅关机的实现原理
优雅关机是调用net/http的srv.Shutdown(ctx)实现的,该办法会:
- 先回绝前面的connection申请;
- 而后再缓缓的解决未处理完毕的申请;
- 当未解决的申请一旦被处理完毕,其connection变成Idle,而后被Close()掉;
func (srv *Server) Shutdown(ctx context.Context) error { ... for _, f := range srv.onShutdown { go f() } ... ticker := time.NewTicker(shutdownPollInterval) defer ticker.Stop() for { if srv.closeIdleConns() { //敞开idle连贯 return lnerr } select { case <-ctx.Done(): //ctx到期,如cancel()被调用 return ctx.Err() case <-ticker.C: } }}
另外,当调用Shutdown()后,srv.ListenAndServer办法将退出,并返回ErrServerClose谬误。