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

@ -117,6 +117,7 @@ type HTTP2Config struct {
Enabled bool `yaml:"enabled"` Enabled bool `yaml:"enabled"`
PushEnabled bool `yaml:"push_enabled"` PushEnabled bool `yaml:"push_enabled"`
H2CEnabled bool `yaml:"h2c_enabled"` H2CEnabled bool `yaml:"h2c_enabled"`
GracefulShutdownTimeout time.Duration `yaml:"graceful_shutdown_timeout"`
} }
// HTTP3Config HTTP/3 (QUIC) 配置。 // HTTP3Config HTTP/3 (QUIC) 配置。

View File

@ -74,6 +74,7 @@ func DefaultConfig() *Config {
IdleTimeout: 120 * time.Second, IdleTimeout: 120 * time.Second,
PushEnabled: false, PushEnabled: false,
H2CEnabled: false, H2CEnabled: false,
GracefulShutdownTimeout: 30 * time.Second,
}, },
SessionTickets: SessionTicketsConfig{ SessionTickets: SessionTicketsConfig{
Enabled: false, Enabled: false,

View File

@ -59,6 +59,15 @@ type Server struct {
// running 服务器运行状态 // running 服务器运行状态
running bool running bool
// pool 连接池
pool *connectionPool
// connWg 连接等待组,用于优雅关闭
connWg sync.WaitGroup
// GracefulShutdownTimeout 优雅关闭超时时间
GracefulShutdownTimeout time.Duration
} }
// NewServer 创建 HTTP/2 服务器。 // NewServer 创建 HTTP/2 服务器。
@ -96,6 +105,11 @@ func NewServer(cfg *config.HTTP2Config, handler fasthttp.RequestHandler, tlsConf
idleTimeout = 120 * time.Second idleTimeout = 120 * time.Second
} }
gracefulTimeout := cfg.GracefulShutdownTimeout
if gracefulTimeout <= 0 {
gracefulTimeout = 30 * time.Second
}
// 创建 HTTP/2 服务器 // 创建 HTTP/2 服务器
h2s := &http2.Server{ h2s := &http2.Server{
MaxConcurrentStreams: uint32(maxConcurrentStreams), MaxConcurrentStreams: uint32(maxConcurrentStreams),
@ -112,6 +126,8 @@ func NewServer(cfg *config.HTTP2Config, handler fasthttp.RequestHandler, tlsConf
config: cfg, config: cfg,
tlsConfig: tlsConfig, tlsConfig: tlsConfig,
handler: handler, handler: handler,
pool: newConnectionPool(),
GracefulShutdownTimeout: gracefulTimeout,
}, nil }, nil
} }
@ -166,6 +182,7 @@ func (s *Server) Serve(ln net.Listener) error {
continue continue
} }
s.connWg.Add(1)
go s.handleConnection(conn) go s.handleConnection(conn)
} }
} }
@ -174,7 +191,11 @@ func (s *Server) Serve(ln net.Listener) error {
// //
// 根据连接类型TLS 或明文)和 ALPN 协商结果,选择合适的协议处理。 // 根据连接类型TLS 或明文)和 ALPN 协商结果,选择合适的协议处理。
func (s *Server) handleConnection(conn net.Conn) { func (s *Server) handleConnection(conn net.Conn) {
key := conn.RemoteAddr().String()
s.pool.add(key, conn)
defer func() { defer func() {
s.pool.remove(key, conn)
s.connWg.Done()
if err := conn.Close(); err != nil { if err := conn.Close(); err != nil {
logging.Error().Err(err).Msg("HTTP/2 connection close error") 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 return nil
} }