diff --git a/internal/config/config.go b/internal/config/config.go index 6c06db9..d408825 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -111,12 +111,13 @@ type VariablesConfig struct { // max_concurrent_streams: 128 // max_header_list_size: "16KB" type HTTP2Config struct { - MaxConcurrentStreams int `yaml:"max_concurrent_streams"` - MaxHeaderListSize int `yaml:"max_header_list_size"` - IdleTimeout time.Duration `yaml:"idle_timeout"` - Enabled bool `yaml:"enabled"` - PushEnabled bool `yaml:"push_enabled"` - H2CEnabled bool `yaml:"h2c_enabled"` + MaxConcurrentStreams int `yaml:"max_concurrent_streams"` + MaxHeaderListSize int `yaml:"max_header_list_size"` + IdleTimeout time.Duration `yaml:"idle_timeout"` + Enabled bool `yaml:"enabled"` + PushEnabled bool `yaml:"push_enabled"` + H2CEnabled bool `yaml:"h2c_enabled"` + GracefulShutdownTimeout time.Duration `yaml:"graceful_shutdown_timeout"` } // HTTP3Config HTTP/3 (QUIC) 配置。 diff --git a/internal/config/defaults.go b/internal/config/defaults.go index f768155..601790e 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -68,12 +68,13 @@ func DefaultConfig() *Config { Preload: false, }, HTTP2: HTTP2Config{ - Enabled: true, - MaxConcurrentStreams: 128, - MaxHeaderListSize: 1048576, // 1MB - IdleTimeout: 120 * time.Second, - PushEnabled: false, - H2CEnabled: false, + Enabled: true, + MaxConcurrentStreams: 128, + MaxHeaderListSize: 1048576, // 1MB + IdleTimeout: 120 * time.Second, + PushEnabled: false, + H2CEnabled: false, + GracefulShutdownTimeout: 30 * time.Second, }, SessionTickets: SessionTicketsConfig{ Enabled: false, diff --git a/internal/http2/server.go b/internal/http2/server.go index b80d152..cc573ce 100644 --- a/internal/http2/server.go +++ b/internal/http2/server.go @@ -59,6 +59,15 @@ type Server struct { // running 服务器运行状态 running bool + + // pool 连接池 + pool *connectionPool + + // connWg 连接等待组,用于优雅关闭 + connWg sync.WaitGroup + + // GracefulShutdownTimeout 优雅关闭超时时间 + GracefulShutdownTimeout time.Duration } // NewServer 创建 HTTP/2 服务器。 @@ -96,6 +105,11 @@ func NewServer(cfg *config.HTTP2Config, handler fasthttp.RequestHandler, tlsConf idleTimeout = 120 * time.Second } + gracefulTimeout := cfg.GracefulShutdownTimeout + if gracefulTimeout <= 0 { + gracefulTimeout = 30 * time.Second + } + // 创建 HTTP/2 服务器 h2s := &http2.Server{ MaxConcurrentStreams: uint32(maxConcurrentStreams), @@ -107,11 +121,13 @@ func NewServer(cfg *config.HTTP2Config, handler fasthttp.RequestHandler, tlsConf } return &Server{ - stopChan: make(chan struct{}), - http2Server: h2s, - config: cfg, - tlsConfig: tlsConfig, - handler: handler, + stopChan: make(chan struct{}), + http2Server: h2s, + config: cfg, + tlsConfig: tlsConfig, + handler: handler, + pool: newConnectionPool(), + GracefulShutdownTimeout: gracefulTimeout, }, nil } @@ -166,6 +182,7 @@ func (s *Server) Serve(ln net.Listener) error { continue } + s.connWg.Add(1) go s.handleConnection(conn) } } @@ -174,7 +191,11 @@ func (s *Server) Serve(ln net.Listener) error { // // 根据连接类型(TLS 或明文)和 ALPN 协商结果,选择合适的协议处理。 func (s *Server) handleConnection(conn net.Conn) { + key := conn.RemoteAddr().String() + s.pool.add(key, conn) defer func() { + s.pool.remove(key, conn) + s.connWg.Done() if err := conn.Close(); err != nil { logging.Error().Err(err).Msg("HTTP/2 connection close error") } @@ -263,7 +284,23 @@ func (s *Server) Stop() error { } } - logging.Info().Msg("HTTP/2 server stopped") + // 关闭所有连接 + s.pool.closeAll() + + // 等待所有连接完成或超时 + done := make(chan struct{}) + go func() { + s.connWg.Wait() + close(done) + }() + + select { + case <-done: + logging.Info().Msg("HTTP/2 server stopped gracefully") + case <-time.After(s.GracefulShutdownTimeout): + logging.Warn().Msg("HTTP/2 server graceful shutdown timed out") + } + return nil }