feat(http2): 实现服务器优雅关闭功能

添加 GracefulShutdownTimeout 配置项,实现连接池管理和优雅关闭逻辑:
- HTTP2Config 新增 graceful_shutdown_timeout 字段(默认30秒)
- Server 添加连接池和等待组跟踪活跃连接
- Stop() 方法等待所有连接完成或超时后再退出

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
xfy 2026-04-13 11:38:01 +08:00
parent 4053634b4c
commit 50a960c539
3 changed files with 57 additions and 18 deletions

View File

@ -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) 配置。

View File

@ -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,

View File

@ -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
}