feat(memory): 整理频率走面板配置(面板 > env > 默认)+ 分时段动态间隔
主人 2026-10-07:「.env 只做兜底…优先从面板配置上取」+「频率必须调…或者动态
分配,比如白天间隔短一点 晚上到了静默时期稍微长一点」。
- memory-tidy.json 新增四键:intervalSec / quietIntervalSec / quietStartHour /
quietEndHour(*int + 指针判定 => 显式 0 是合法值、缺位才回落)
- 优先级逐键三档:面板 > env(既有键,未增删)> 代码默认;坏值不覆盖 + WARN,
且不启动失败
- 动态间隔由纯函数 intervalAt(at) 决定,调度侧每一拍现算 => 跑完按当时时段重算
- 🔴 语义变更(有意,代码注释已登记,待补设计修订):安静时段从「唯一可跑时段」
变成「降频时段」—— 旧的「安静窗外一律 continue」被删,否则 intervalSec 永远
是空壳(白天唤醒必被跳过);窗口仍决定档位与补跑判据
- 6 个变异(含「加回旧的那道门」=> 端到端用例红)
This commit is contained in:
1 parent
6deab2e836
commit
d680390300
11 files changed
+832
-54
No files matched your search
@@ -253,3 +253,70 @@ func TestApplyMemoryTidyTuning_ReadsDataDirConfig(t *testing.T) {
|
||||
t.Fatalf("坏配置时 cfg = %+v, want 回落零值(默认值由 normalize 填)", cfg)
|
||||
}
|
||||
}
|
||||
|
||||
// TestApplyMemoryTidyTuning_ScheduleKnobs 钉住**整理频率**四键在组合根上的接线:
|
||||
// 面板($DATA_DIR/config/memory-tidy.json)优先、`.env` 兜底 —— 主人 2026-10-07
|
||||
// 口径「.env 只做兜底用 …… 这些键优先从面板配置上取」。
|
||||
//
|
||||
// 这里只断言「叠完之后 cfg 里是什么」,不重复 memory 包的优先级链用例:组合根这一层
|
||||
// 要证明的是**那个文件真的被读了、真的落到了 cfg 上**(少这一句,面板改了频率也无效,
|
||||
// 而不会有任何用例变红)。
|
||||
func TestApplyMemoryTidyTuning_ScheduleKnobs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// env 层:与面板值故意对立。
|
||||
env := config.MemoryTidyConfig{Enabled: true, IntervalSec: 7200, QuietStartHour: 23, QuietEndHour: 7}
|
||||
|
||||
newApp := func(dataDir string) *app {
|
||||
return &app{cfg: &config.Config{DataDir: dataDir}, log: tidyTestLog()}
|
||||
}
|
||||
apply := func(dataDir string) memory.TidyConfig {
|
||||
cfg := memory.TidyConfigFromConfig(env)
|
||||
newApp(dataDir).applyMemoryTidyTuning(&cfg)
|
||||
return cfg
|
||||
}
|
||||
|
||||
// ① 面板四键都写了 ⇒ 四个都用面板值(覆盖 `.env`)。
|
||||
dataDir := t.TempDir()
|
||||
dir := filepath.Join(dataDir, "config")
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||
t.Fatalf("mkdir: %v", err)
|
||||
}
|
||||
path := filepath.Join(dir, "memory-tidy.json")
|
||||
body := `{"intervalSec": 3600, "quietIntervalSec": 10800, "quietStartHour": 1, "quietEndHour": 5}`
|
||||
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
|
||||
t.Fatalf("write: %v", err)
|
||||
}
|
||||
cfg := apply(dataDir)
|
||||
if cfg.IntervalSec != 3600 {
|
||||
t.Fatalf("intervalSec = %d, want 3600(面板优先)", cfg.IntervalSec)
|
||||
}
|
||||
if cfg.QuietIntervalSec != 10800 {
|
||||
t.Fatalf("quietIntervalSec = %d, want 10800(面板优先)", cfg.QuietIntervalSec)
|
||||
}
|
||||
if cfg.QuietStartHour != 1 || cfg.QuietEndHour != 5 {
|
||||
t.Fatalf("安静时段 = %02d:00-%02d:00, want 01:00-05:00(面板优先)",
|
||||
cfg.QuietStartHour, cfg.QuietEndHour)
|
||||
}
|
||||
|
||||
// ② 文件不存在 ⇒ 四键保持 `.env` 值(面板只是「能覆盖」,不是「必须有」)。
|
||||
empty := t.TempDir()
|
||||
cfg = apply(empty)
|
||||
if cfg.IntervalSec != 7200 || cfg.QuietStartHour != 23 || cfg.QuietEndHour != 7 {
|
||||
t.Fatalf("没配过时应保持 env 值,得到 %+v", cfg)
|
||||
}
|
||||
|
||||
// ③ 坏文件(类型写错)⇒ 整份回落 `.env`,且**不启动失败**:组合根照旧拿到
|
||||
// 可用的 cfg(一个坏键不得让整理停摆)。
|
||||
if err := os.WriteFile(path, []byte(`{"intervalSec": "3600"}`), 0o600); err != nil {
|
||||
t.Fatalf("write broken: %v", err)
|
||||
}
|
||||
cfg = apply(dataDir)
|
||||
if cfg.IntervalSec != 7200 || cfg.QuietStartHour != 23 || cfg.QuietEndHour != 7 {
|
||||
t.Fatalf("坏文件时应回落 env 值,得到 %+v", cfg)
|
||||
}
|
||||
if cfg.QuietIntervalSec != 0 {
|
||||
t.Fatalf("坏文件时 quietIntervalSec 应当是零值(由 normalize 取 = intervalSec),得到 %d",
|
||||
cfg.QuietIntervalSec)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user