fix(setting): runtime config 全局变量加 sync.RWMutex 保护,避免半写状态
TTSOptions / TTSTimeout / TTSConfigErr / Auth.APIKeys / CORS 在运行期会被
LoadRuntimeConfig(PUT /api/settings 触发)整体替换,struct 整体赋值不是原子的,
若 TTS 请求正并发读,可能拿到半写状态。单用户场景概率低,属正确性隐患。
改动:
- setting/config.go: 把可变运行时配置迁到包内私有变量,新增 ttsMu
(sync.RWMutex) 统一保护,提供 Get*/Set* 访问器
- GetTTSOptions/SetTTSOptions: 值类型快照,读端无锁开销
- GetTTSTimeout/SetTTSTimeout
- GetTTSConfigErr/SetTTSConfigErr
- GetAuthAPIKeys/SetAuthAPIKeys: 拷贝进出,防止外部持有底层 slice
- GetCORSAllowAll/GetCORSOrigins/SetCORS: AllowAll 和 Origins 拆开,
避免热路径 CORSConfig 整体读时锁粒度过粗
- 删除导出可变全局 var TTSOptions/TTSTimeout/TTSConfigErr/Auth/CORS,
编译期强制所有读写走 Get*/Set*
- Server.Port/TrustedProxyHops/SetupToken 仅启动期写,运行期无并发修改,
保持原状不加锁
- LoadRuntimeConfig/InitAuthConfig/InitCORSConfig 全切到 Set*
- CheckEnvironmentVariables/LogStartupSummary 一次性拿快照,
缩短锁占用窗口,避免多次 log.Printf 之间数据被替换
调用点:
- controller/tts.go: 热路径 opts := setting.GetTTSOptions(),
context 超时走 GetTTSTimeout(),/health 块用 GetTTSConfigErr
- controller/settings.go: 写改 SetAuthAPIKeys/SetCORS
- controller/setup.go: 写改 SetAuthAPIKeys
- middleware/auth.go: 鉴权改 GetAuthAPIKeys()(在 RLock 下拿拷贝)
- middleware/admin_auth.go: 同上
- middleware/cors.go: matchOrigin 改 GetCORSAllowAll/GetCORSOrigins
读多写少,RWMutex 读路径不互斥,不会拖慢热路径。
This commit is contained in:
+9
-12
@@ -261,7 +261,7 @@ type SettingsAuthKeyRequest struct {
|
||||
}
|
||||
|
||||
// SettingsAuthKeyHandler PUT /api/settings/auth-key
|
||||
// 鉴权: RequireAdmin。改完立即更新 setting.Auth.APIKeys(进程内生效),
|
||||
// 鉴权: RequireAdmin。改完立即刷新鉴权 key 列表(setting.SetAuthAPIKeys,进程内生效),
|
||||
// 下一个请求就用新 key — admin 自己改完要等下一次请求才能验证(避免改完立刻自踢)。
|
||||
func SettingsAuthKeyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPut {
|
||||
@@ -292,7 +292,7 @@ func SettingsAuthKeyHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
// 立即生效:不重新 LoadRuntimeConfig(那会覆盖其它字段),
|
||||
// 只单独刷新 Auth.APIKeys
|
||||
setting.Auth.APIKeys = []string{key}
|
||||
setting.SetAuthAPIKeys([]string{key})
|
||||
log.Printf("[settings] auth_key updated, runtime active (next request uses new key)")
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"ok": true})
|
||||
@@ -309,7 +309,7 @@ type SettingsCORSRequest struct {
|
||||
}
|
||||
|
||||
// SettingsCORSHandler PUT /api/settings/cors
|
||||
// 鉴权: RequireAdmin。改完立即更新 setting.CORS(进程内生效,跨域请求从下个请求开始按新配置)。
|
||||
// 鉴权: RequireAdmin。改完立即刷新 CORS(setting.SetCORS,进程内生效,跨域请求从下个请求开始按新配置)。
|
||||
// 同源豁免由 middleware/cors.go 的 isSameOrigin 处理,不在这里管。
|
||||
func SettingsCORSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPut {
|
||||
@@ -369,7 +369,7 @@ func SettingsCORSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 立即刷新 setting.CORS,跨域请求从下个请求开始按新配置生效
|
||||
// 立即刷新 CORS(setting.SetCORS),跨域请求从下个请求开始按新配置生效
|
||||
// 复用 LoadRuntimeConfig 的解析逻辑(只取 cors 部分,避免覆盖其它运行时字段)
|
||||
corsAllowAll, _ := s.SettingsGetBool("cors_allow_all", false)
|
||||
originsStr := ""
|
||||
@@ -377,20 +377,17 @@ func SettingsCORSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
originsStr = v
|
||||
}
|
||||
if corsAllowAll {
|
||||
setting.CORS.AllowAll = true
|
||||
setting.CORS.Origins = nil
|
||||
setting.SetCORS(true, nil)
|
||||
} else if originsStr != "" {
|
||||
setting.CORS.AllowAll = false
|
||||
setting.CORS.Origins = setting.SplitOriginsForCORS(originsStr)
|
||||
setting.SetCORS(false, setting.SplitOriginsForCORS(originsStr))
|
||||
} else {
|
||||
setting.CORS.AllowAll = false
|
||||
setting.CORS.Origins = nil
|
||||
setting.SetCORS(false, nil)
|
||||
}
|
||||
log.Printf("[settings] cors updated (allow_all=%v origins=%q), runtime active", setting.CORS.AllowAll, originsStr)
|
||||
log.Printf("[settings] cors updated (allow_all=%v origins=%q), runtime active", setting.GetCORSAllowAll(), originsStr)
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"ok": true,
|
||||
"allow_all": setting.CORS.AllowAll,
|
||||
"allow_all": setting.GetCORSAllowAll(),
|
||||
"origins": originsStr,
|
||||
"cors_active": true,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user