🐛 fix(server): 增加优雅退出与请求超时保护

- 新增 SIGINT/SIGTERM 信号处理与 http.Server.Shutdown,退出前确保统计数据保存、数据库正常关闭
- 为 http.Server 设置 ReadHeaderTimeout/ReadTimeout/WriteTimeout/IdleTimeout,防止慢客户端长期占用连接
- 全局配置指针改为 atomic.Pointer 并提供 GetAppConfig 访问器,消除配置热更新时的数据竞争,同时删除冗余的 manager.config 字段
- 请求统计九组计数器重构为 map[string]*atomic.Int64,统一 incrementStat/getStatsSnapshot 访问,精简约 40 行样板代码
- go mod tidy 清理 go.mod 与 go.sum 中的冗余依赖条目
This commit is contained in:
chenxin committed 2026-09-29 19:47:04 +08:00
1 parent 6981148727
commit d710d382ee
12 files changed
+125 -305

No files matched your search

+18 -21
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"log"
"sync"
"sync/atomic"
"github.com/spf13/viper"
)
@@ -67,17 +68,21 @@ type DeviceKeyPoolConfig struct {
// ConfigManager 配置管理器
type ConfigManager struct {
mu sync.RWMutex
config *Config
configPath string
callbacks []func(*Config)
}
var (
// AppConfig 全局配置实例
AppConfig *Config
// appConfig 全局配置实例(原子指针,热更新替换时读取侧无数据竞争)
appConfig atomic.Pointer[Config]
manager *ConfigManager
)
// GetAppConfig 获取当前配置,未加载时返回 nil
func GetAppConfig() *Config {
return appConfig.Load()
}
// NewConfigManager 创建配置管理器
func NewConfigManager() *ConfigManager {
return &ConfigManager{
@@ -109,10 +114,7 @@ func LoadConfig(configPath string) error {
}
// 更新配置
manager.mu.Lock()
manager.config = newConfig
AppConfig = newConfig
manager.mu.Unlock()
appConfig.Store(newConfig)
return nil
}
@@ -155,18 +157,11 @@ func setDefaults() {
// GetConfig 获取配置实例
func GetConfig() *Config {
if manager != nil {
manager.mu.RLock()
defer manager.mu.RUnlock()
if manager.config != nil {
return manager.config
}
if cfg := appConfig.Load(); cfg != nil {
return cfg
}
if AppConfig == nil {
log.Fatal("配置未初始化,请先调用 LoadConfig")
}
return AppConfig
log.Fatal("配置未初始化,请先调用 LoadConfig")
return nil
}
// ReloadConfig 重新加载配置文件
@@ -196,9 +191,11 @@ func ReloadConfig() error {
// 更新配置
manager.mu.Lock()
oldAlgorithm := manager.config.Fanqie.Algorithm
manager.config = newConfig
AppConfig = newConfig
var oldAlgorithm string
if old := appConfig.Load(); old != nil {
oldAlgorithm = old.Fanqie.Algorithm
}
appConfig.Store(newConfig)
callbacks := make([]func(*Config), len(manager.callbacks))
copy(callbacks, manager.callbacks)
manager.mu.Unlock()