feat: support graceful shutdown (#2469) (#2475)

This commit is contained in:
XG
2023-03-13 19:21:56 +08:00
committed by GitHub
parent e6c97410ef
commit 8c07f1a42c
4 changed files with 53 additions and 44 deletions

View File

@ -142,7 +142,6 @@ const (
specialMethodNameInit = "Init"
specialMethodNameShut = "Shut"
specialMethodNameIndex = "Index"
gracefulShutdownTimeout = 5 * time.Second
)
const (

View File

@ -69,9 +69,6 @@ func serverProcessInit() {
}
}
// Signal handler.
go handleProcessSignal()
// Process message handler.
// It enabled only a graceful feature is enabled.
if gracefulEnabled {
@ -258,6 +255,7 @@ func (s *Server) Start() error {
s.initOpenApi()
s.doServiceRegister()
s.doRouterMapDump()
return nil
}
@ -425,7 +423,11 @@ func (s *Server) Run() {
if err := s.Start(); err != nil {
s.Logger().Fatalf(ctx, `%+v`, err)
}
// Blocking using channel.
// Signal handler.
handleProcessSignal()
// Blocking using channel for graceful restart.
<-s.closeChan
// Remove plugins.
if len(s.plugins) > 0 {

View File

@ -252,6 +252,9 @@ type ServerConfig struct {
// GracefulTimeout set the maximum survival time (seconds) of the parent process.
GracefulTimeout uint8 `json:"gracefulTimeout"`
// GracefulShutdownTimeout set the maximum survival time (seconds) before stopping the server.
GracefulShutdownTimeout uint8 `json:"gracefulShutdownTimeout"`
}
// NewConfig creates and returns a ServerConfig object with default configurations.
@ -259,44 +262,45 @@ type ServerConfig struct {
// some pointer attributes that may be shared in different servers.
func NewConfig() ServerConfig {
return ServerConfig{
Name: DefaultServerName,
Address: ":0",
HTTPSAddr: "",
Listeners: nil,
Handler: nil,
ReadTimeout: 60 * time.Second,
WriteTimeout: 0, // No timeout.
IdleTimeout: 60 * time.Second,
MaxHeaderBytes: 10240, // 10KB
KeepAlive: true,
IndexFiles: []string{"index.html", "index.htm"},
IndexFolder: false,
ServerAgent: "GoFrame HTTP Server",
ServerRoot: "",
StaticPaths: make([]staticPathItem, 0),
FileServerEnabled: false,
CookieMaxAge: time.Hour * 24 * 365,
CookiePath: "/",
CookieDomain: "",
SessionIdName: "gfsessionid",
SessionPath: gsession.DefaultStorageFilePath,
SessionMaxAge: time.Hour * 24,
SessionCookieOutput: true,
SessionCookieMaxAge: time.Hour * 24,
Logger: glog.New(),
LogLevel: "all",
LogStdout: true,
ErrorStack: true,
ErrorLogEnabled: true,
ErrorLogPattern: "error-{Ymd}.log",
AccessLogEnabled: false,
AccessLogPattern: "access-{Ymd}.log",
DumpRouterMap: true,
ClientMaxBodySize: 8 * 1024 * 1024, // 8MB
FormParsingMemory: 1024 * 1024, // 1MB
Rewrites: make(map[string]string),
Graceful: false,
GracefulTimeout: 2, // seconds
Name: DefaultServerName,
Address: ":0",
HTTPSAddr: "",
Listeners: nil,
Handler: nil,
ReadTimeout: 60 * time.Second,
WriteTimeout: 0, // No timeout.
IdleTimeout: 60 * time.Second,
MaxHeaderBytes: 10240, // 10KB
KeepAlive: true,
IndexFiles: []string{"index.html", "index.htm"},
IndexFolder: false,
ServerAgent: "GoFrame HTTP Server",
ServerRoot: "",
StaticPaths: make([]staticPathItem, 0),
FileServerEnabled: false,
CookieMaxAge: time.Hour * 24 * 365,
CookiePath: "/",
CookieDomain: "",
SessionIdName: "gfsessionid",
SessionPath: gsession.DefaultStorageFilePath,
SessionMaxAge: time.Hour * 24,
SessionCookieOutput: true,
SessionCookieMaxAge: time.Hour * 24,
Logger: glog.New(),
LogLevel: "all",
LogStdout: true,
ErrorStack: true,
ErrorLogEnabled: true,
ErrorLogPattern: "error-{Ymd}.log",
AccessLogEnabled: false,
AccessLogPattern: "access-{Ymd}.log",
DumpRouterMap: true,
ClientMaxBodySize: 8 * 1024 * 1024, // 8MB
FormParsingMemory: 1024 * 1024, // 1MB
Rewrites: make(map[string]string),
Graceful: false,
GracefulTimeout: 2, // seconds
GracefulShutdownTimeout: 5, // seconds
}
}

View File

@ -16,6 +16,7 @@ import (
"os"
"strconv"
"sync"
"time"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
@ -231,7 +232,10 @@ func (s *gracefulServer) shutdown(ctx context.Context) {
if s.status == ServerStatusStopped {
return
}
timeoutCtx, cancelFunc := context.WithTimeout(ctx, gracefulShutdownTimeout)
timeoutCtx, cancelFunc := context.WithTimeout(
ctx,
time.Duration(s.server.config.GracefulShutdownTimeout)*time.Second,
)
defer cancelFunc()
if err := s.httpServer.Shutdown(timeoutCtx); err != nil {
s.server.Logger().Errorf(