From 5bb67f13a0ea5df35bfa836f14332a554c626cd0 Mon Sep 17 00:00:00 2001 From: xfy Date: Mon, 13 Apr 2026 11:25:47 +0800 Subject: [PATCH] =?UTF-8?q?refactor(app):=20=E4=BD=BF=E7=94=A8=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8C=96=E5=85=B3=E9=97=AD=E8=B6=85=E6=97=B6=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3=E7=A1=AC=E7=BC=96=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除硬编码的 shutdownTimeout 变量,改用配置中的 Shutdown.GracefulTimeout 和 Shutdown.FastTimeout: - handleSignal 从配置读取超时值 - gracefulUpgrade 使用配置的优雅停止超时 - 添加防御性 nil-check 确保配置和服务器实例存在 - Windows 版本同步更新 Windows 和 Unix 平台行为一致化。 Co-Authored-By: Claude Opus 4.6 --- internal/app/app.go | 46 ++++++++++++++++++++++++++++--------- internal/app/app_windows.go | 9 +++++--- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index 8f054c7..5e714a0 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -53,12 +53,6 @@ var ( BuildPlatform = "unknown" ) -// 应用状态。 -var ( - // shutdownTimeout 优雅停止超时时间 - shutdownTimeout = 30 * time.Second -) - // App 应用程序结构。 // // 管理服务器的完整生命周期,包括 HTTP 服务器、HTTP/3 服务器、Stream 服务器 @@ -349,22 +343,42 @@ func (a *App) setupSignalHandlers(sigChan chan<- os.Signal) { // handleSignal 处理信号,返回 false 表示退出。 func (a *App) handleSignal(sig os.Signal) bool { + // 防御性 nil-check:确保 a.cfg 不为 nil + if a.cfg == nil { + a.logger.Error().Msg("信号处理失败: 配置为 nil,使用默认超时") + // 使用默认超时继续处理信号 + a.cfg = &config.Config{ + Shutdown: config.ShutdownConfig{ + GracefulTimeout: 30 * time.Second, + FastTimeout: 5 * time.Second, + }, + } + } + switch sig { case syscall.SIGQUIT: // 优雅停止:等待请求完成 - a.logger.LogSignal("SIGQUIT", fmt.Sprintf("优雅停止(等待 %v)", shutdownTimeout)) + timeout := a.cfg.Shutdown.GracefulTimeout + if timeout <= 0 { + timeout = 30 * time.Second // 默认值 + } + a.logger.LogSignal("SIGQUIT", fmt.Sprintf("优雅停止(等待 %v)", timeout)) a.shutdownHTTP2() a.shutdownHTTP3() - _ = a.srv.GracefulStop(shutdownTimeout) //nolint:errcheck + _ = a.srv.GracefulStop(timeout) //nolint:errcheck return false case syscall.SIGTERM, syscall.SIGINT: // 快速停止 + timeout := a.cfg.Shutdown.FastTimeout + if timeout <= 0 { + timeout = 5 * time.Second // 默认值 + } sigTyped := sig.(syscall.Signal) //nolint:errcheck // 类型断言 a.logger.LogSignal(sigName(sigTyped), "停止服务器") a.shutdownHTTP2() a.shutdownHTTP3() - _ = a.srv.Stop() //nolint:errcheck + _ = a.srv.StopWithTimeout(timeout) //nolint:errcheck // 使用新方法 return false case syscall.SIGHUP: @@ -442,6 +456,12 @@ func (a *App) gracefulUpgrade() { return } + // 防御性 nil-check:确保 srv 不为 nil + if a.srv == nil { + a.logger.Error().Msg("热升级失败: 服务器实例为 nil") + return + } + // 尝试从服务器获取监听器 listeners := a.srv.GetListeners() if len(listeners) == 0 { @@ -461,10 +481,14 @@ func (a *App) gracefulUpgrade() { a.logger.LogStartup("热升级已启动,新进程正在接管", nil) - // 当前进程优雅停止 + // 当前进程优雅停止 - 使用配置的超时 + timeout := a.cfg.Shutdown.GracefulTimeout + if timeout <= 0 { + timeout = 30 * time.Second + } a.shutdownHTTP2() a.shutdownHTTP3() - _ = a.srv.GracefulStop(shutdownTimeout) //nolint:errcheck + _ = a.srv.GracefulStop(timeout) //nolint:errcheck } // sigName 返回信号名称(用于日志输出)。 diff --git a/internal/app/app_windows.go b/internal/app/app_windows.go index e4f8ef7..d84c491 100644 --- a/internal/app/app_windows.go +++ b/internal/app/app_windows.go @@ -36,8 +36,6 @@ var ( BuildPlatform = "unknown" ) -var shutdownTimeout = 30 * time.Second - // App 应用程序结构(Windows 版本)。 type App struct { cfgPath string @@ -282,10 +280,15 @@ func (a *App) setupSignalHandlers(sigChan chan<- os.Signal) { func (a *App) handleSignal(sig os.Signal) bool { switch sig { case syscall.SIGTERM, syscall.SIGINT: + // 快速停止 + timeout := a.cfg.Shutdown.FastTimeout + if timeout <= 0 { + timeout = 5 * time.Second // 默认值 + } a.logger.LogSignal(sigName(sig.(syscall.Signal)), "停止服务器") a.shutdownHTTP2() a.shutdownHTTP3() - _ = a.srv.Stop() + _ = a.srv.StopWithTimeout(timeout) //nolint:errcheck // 使用新方法 return false default: a.logger.Info().Str("signal", sig.String()).Msg("收到信号(Windows 忽略)")