fix(memory): 冷启动放宽改为一次性 + 试算轮区分「没候选」与「向量不可用」
review round1 的 p1/p2 收口(commit 5967272 之后)。
p1:旧实现 `warmed` 只在 2xx 之后才翻 ⇒ 注释里写的「只在第一次成功响应之前」
实际是「服务坏着的全部时间」。reviewer 实测「接受连接但永不回包」时**每次**调用
都等满 30s(fail-fast 变 fail-slow):审查 20s 预算被一次吃光、索引写入拖成
8×30s、开机探针阻塞 30s。
- `warmupLeft` 改为**一次性许可**(CompareAndSwap 取走即失效,成败都算花掉)
⇒ 挂死时只有第一个请求慢一次,此后一律 DefaultRequestTimeout。
- `warmupTimeout` 30s → 8s:与常态 5s 同一量级(≤2×),且严格小于审查总预算
20s(一次冷启动不许吃光整轮);两条界都由 TestDefaultRequestTimeout 守住。
- 放宽被花掉且没成功时留一条 WARN(事后可复核「第一个请求」这个判据)。
- 更正两处自述:api.go 的「不会被 30s 拖住」与 budget.go 的不变式说明(批次形状
永远按稳态超时推导;冷启动只放宽第一个请求的截止时刻)。
- p2:删掉零调用者的 `WithRequestTimeout` —— 单次超时只允许改常量,批次上限与它
同源并由编译期/常量断言复核。
p2:试算轮在向量源不可用时 `RecallMode` 与「没有候选可比」同为空串。
- `recallLedger` 增 `unavailable` 计数 + `noteUnavailable()`(strictRecall 失败
那一笔记一笔);试算汇总行新增 `recall_unavailable_partitions`,**成败都记**。
- 不扩 `recallMode` 取值集合:失败那一路不序列化 result(响应是
500 tidy_recall_unavailable),新取值只会出现在日志里却要动一次契约,不划算。
测试:三种失败形态 × 两次调用的耗时断言(连接被拒 / 500 / 永不回包),
试算轮的「不可用」与「没候选」两态日志断言;两处变异自证(warmupTimeout 调回
30s ⇒ TestDefaultRequestTimeout 红;去掉 noteUnavailable ⇒ 试算汇总行退化成
recall_mode="" + recall_unavailable_partitions=0)。
This commit is contained in:
1 parent
59672720bd
commit
6c30ca540a
7 files changed
+273
-72
No files matched your search
@@ -151,24 +151,55 @@ func TestTidyRunLog_RecallModeEmptyWhenNoPairs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestTidyDryRun_RecallModeIsActualNotConfigured 是**试算轮**(面板那一条)的同口径
|
||||
// 回归:配了 embedder 但向量不可用 ⇒ 试算如实报错(严格模式),且返回的 RecallMode
|
||||
// **不**写成 embedding。
|
||||
func TestTidyDryRun_RecallModeIsActualNotConfigured(t *testing.T) {
|
||||
// TestTidyDryRun_UnavailableIsDistinctFromNoCandidates 钉 reviewer round1 p2:
|
||||
// 试算轮「尝试过召回但向量源不可用」与「没有候选可比」**必须能区分**。
|
||||
//
|
||||
// 两者的 `RecallMode` 都是空串(都不曾产出相似度,报 embedding/lexical 都是假的),
|
||||
// 区分点在 `recall_unavailable_partitions`:不可用时为 1,没候选时为 0。调用方
|
||||
// (面板)另有一条更硬的区分 —— 失败那一路不序列化 result,直接是
|
||||
// `500 tidy_recall_unavailable`。
|
||||
func TestTidyDryRun_UnavailableIsDistinctFromNoCandidates(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
store := newTestStore(t)
|
||||
seedDryRunFixture(t, store)
|
||||
|
||||
emb := failingEmbedder{err: errors.New("embedding: request: context deadline exceeded")}
|
||||
tr, _ := newLogCaptureTidier(t, store, tidyTestCfg(0.80), emb)
|
||||
out, err := tr.DryRun(ctx)
|
||||
if !errors.Is(err, ErrTidyRecallUnavailable) {
|
||||
t.Fatalf("试算轮必须如实上报不可用,err = %v", err)
|
||||
}
|
||||
if out.RecallMode == tidyRecallEmbedding {
|
||||
t.Fatalf("向量不可用却把 RecallMode 报成 embedding(配置态口径):%q", out.RecallMode)
|
||||
}
|
||||
t.Run("向量源不可用", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
store := newTestStore(t)
|
||||
seedDryRunFixture(t, store)
|
||||
|
||||
emb := failingEmbedder{err: errors.New("embedding: request: context deadline exceeded")}
|
||||
tr, buf := newLogCaptureTidier(t, store, tidyTestCfg(0.80), emb)
|
||||
out, err := tr.DryRun(context.Background())
|
||||
if !errors.Is(err, ErrTidyRecallUnavailable) {
|
||||
t.Fatalf("试算轮必须如实上报不可用,err = %v", err)
|
||||
}
|
||||
if out.RecallMode == tidyRecallEmbedding {
|
||||
t.Fatalf("向量不可用却把 RecallMode 报成 embedding(配置态口径):%q", out.RecallMode)
|
||||
}
|
||||
line := lastLogLine(t, buf, "memory tidy dry-run finished")
|
||||
if !strings.Contains(line, "recall_unavailable_partitions=1") {
|
||||
t.Fatalf("汇总行必须写出「尝试过但不可用」的计数,实际:%s", line)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("没有候选可比", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
store := newTestStore(t)
|
||||
base := tidyTestTime(t)
|
||||
seedTidyItem(t, store, habitItem(fixtureHabitShort, base, 0.9))
|
||||
|
||||
emb := failingEmbedder{err: errors.New("embedding: request: context deadline exceeded")}
|
||||
tr, buf := newLogCaptureTidier(t, store, tidyTestCfg(0.80), emb)
|
||||
if _, err := tr.DryRun(context.Background()); err != nil {
|
||||
t.Fatalf("没有对可比时试算不该报错:%v", err)
|
||||
}
|
||||
line := lastLogLine(t, buf, "memory tidy dry-run finished")
|
||||
if !strings.Contains(line, "recall_unavailable_partitions=0") {
|
||||
t.Fatalf("没候选不是「不可用」,计数必须为 0,实际:%s", line)
|
||||
}
|
||||
if !strings.Contains(line, `recall_mode=""`) {
|
||||
t.Fatalf("没候选时来源为空串,实际:%s", line)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// lastLogLine 返回 buffer 里最后一条含 marker 的日志行。
|
||||
|
||||
Reference in new issue
Block a user