ConfigManager Fail-open Anti-pattern¶
概念概覽
問題根源¶
核心知識¶
問題根源¶
main.go:198 ConfigManager 初始化失敗只記錄 warn 並繼續啟動。但系統中有兩個 fail-closed 依賴:
player_inventory_service.go:961:限時道具發放直接讀取 config,init 失敗 → nil pointer → runtime panicdungeon_service.go:291:dungeon config 取用同樣是 fail-closed 依賴
正確設計原則¶
fail-open 元件:Redis rate limiter(Redis 故障 → 跳過限速,可用性優先)
fail-closed 依賴:ConfigManager(失敗 → 某些功能會 panic,不可繼續啟動)
修正:在 production 環境,ConfigManager init 失敗應呼叫 log.Fatal,確保 pod crash 並觸發 k8s restart,而不是啟動一個半壞的 server。
fail-open 僅適合本地開發環境,確保開發者不需要完整依賴就能跑起服務。
經驗教訓¶
-
設計 fail-open 元件時,必須明確列出所有下游是否有 fail-closed 依賴
-
startup 的 warn-and-continue 是隱性的 fail-open 設計,需要特別審查
-
production 環境讓服務以損壞狀態啟動,比 crash 重啟更危險
常見陷阱¶
-
將 fail-open 作為「寬鬆」的預設行為,未區分 production 和 development 環境
-
初始化錯誤只 log 不 fatal,導致服務看似正常啟動但實際上缺失關鍵依賴
最佳實踐¶
-
每個可選依賴在初始化時明確標記為 fail-open 或 fail-closed,並在 code review 中審查
-
production 環境的 startup 代碼應有明確的 fatal 守衛,非可選依賴一律 fatal
-
使用環境變數區分 production fatal vs development warn-and-continue
相關概念¶
來源 Sessions¶
| 日期 | Session | 貢獻摘要 |
|---|---|---|
| 2026-03-17 | 056f9176-f6b2-4663-9b7e-19679837f204 | 具體說明了 ConfigManager fail-open 在有 fail-closed 依賴場景下為何是 P0 bug,以及 startup fatal 的正確設計 |