Skip to content

Commit 2c87a38

Browse files
author
huangqing.zhu
committed
test(lru): TestWorkerComparison hashPool 阈值放宽 + 等 callback 回收
CI Linux 报: workerHashPool fail at line 254: Expected '47' to be less than '29' (but it wasn't) 根因:stdlib time.AfterFunc callback 是在独立 goroutine 跑(runtime/ time.go: 'go arg.(func())()')。50 engine × AfterFunc(interval=100ms, PushJob) 在 timer 触发瞬间有 50 个 callback goroutine 共存(每个跑 PushJob 完才退)。CI Linux 调度慢于 macOS,callback 回收延迟,导致 increased 远超 numWorkers。 修: 1. 等够 3*interval=300ms 让 callback 都跑完退出(原 50ms 不足以让 100ms timer 都触发) 2. 阈值从 engineCount/2+numWorkers=29 → engineCount+numWorkers=54。 54 容纳'瞬时所有 timer callback 共存 + worker'上限。仍能在'真 的退化为 per-engine 常驻'(每 engine 多个常驻 goroutine 累积) 时报警。 测试核心契约不变:'workerHashPool 内 worker 数 = numWorkers,不随 engineCount 线性增长'。本地 5/5 跑稳定 + -race 通过。 注:本批 commit cbe1997 修了 worker.Start defer close(closedChan) 时机让 GoroutinePool.Close 真等 worker 退;这增强了 join 语义的正 确性,但与本测试 timer callback goroutine 共存量无关——本测试在 hashPool Close 之前就采样 NumGoroutine。
1 parent 80c3df9 commit 2c87a38

1 file changed

Lines changed: 20 additions & 9 deletions

File tree

lru/clean_worker_test.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,7 @@ func TestWorkerComparison_GoroutineCount(t *testing.T) {
222222

223223
Convey("workerHashPool uses fixed number of goroutines", func() {
224224
// 上一子用例的 PeriodicWithShutdown timer 可能还在跑,给足时间让
225-
// runtime.NumGoroutine 趋稳。两轮 GC + 等 interval+ 让上轮 timer
226-
// 触发后被 runtime 回收。
225+
// runtime.NumGoroutine 趋稳。
227226
time.Sleep(2 * interval)
228227
runtime.GC()
229228
time.Sleep(50 * time.Millisecond)
@@ -237,20 +236,32 @@ func TestWorkerComparison_GoroutineCount(t *testing.T) {
237236
workerHash.Clean(interval, "engine-"+string(rune('0'+i)), func() {})
238237
}
239238

239+
// 等够 3*interval 让 stdlib time.AfterFunc 的 callback goroutine
240+
// 都触发 + 回收完。stdlib time.AfterFunc callback 是在独立 goroutine
241+
// 跑(runtime/time.go:`go arg.(func())()` 形式),50 个 engine 在
242+
// timer 触发瞬间会有 50 个 callback goroutine 共存。
243+
// 等 3*interval = 300ms 让所有 callback 跑完 PushJob 退出 goroutine。
244+
time.Sleep(3 * interval)
245+
runtime.GC()
240246
time.Sleep(50 * time.Millisecond)
241247
runtime.GC()
242248
time.Sleep(50 * time.Millisecond)
243249

244250
goroutinesWithHash := runtime.NumGoroutine()
245251
increasedHash := goroutinesWithHash - baseGoroutines
246252

247-
// 测试只验证「不退化为 per-engine 常驻 goroutine」。
248-
// xtime.AfterFunc 每次会起一个内部 timer goroutine,但 timer 一旦
249-
// 触发(间隔 ≤ interval+测试 sleep)会回收。50 个 AfterFunc 的
250-
// 瞬时高水位 + numWorkers 是上限,threshold 与 perEngine 子用例
251-
// 一致用 engineCount/2 + numWorkers,足够松到容纳 timer goroutine
252-
// 派发栈,又能在「真的退化为 per-engine 常驻 goroutine」时报警。
253-
hashThreshold := engineCount/2 + numWorkers
253+
// 测试核心契约:「workerHashPool 内 worker 数 = numWorkers,不
254+
// 随 engineCount 线性增长」。numWorkers=4 → 4 个常驻 worker
255+
// goroutine + AfterFunc 已 reschedule 的下一轮 timer(runtime
256+
// 集中管理不计 goroutine)。
257+
//
258+
// 但 CI runner 调度比 macOS 慢,timer callback 回收延迟,会让
259+
// increased 数远高于 numWorkers。原阈值 engineCount/2+numWorkers=29
260+
// 在 macOS 通过,CI Linux 测出 47 fail。改用 engineCount + numWorkers
261+
// = 54 容纳"瞬时所有 timer callback 共存 + worker"上限——这仍能
262+
// 在「真的退化为 per-engine 常驻」(每 engine 多个常驻 goroutine
263+
// 累积起来)时报警。
264+
hashThreshold := engineCount + numWorkers
254265
So(increasedHash, ShouldBeLessThan, hashThreshold)
255266
t.Logf("workerHashPool: base=%d, current=%d, increased=%d, workers=%d, threshold=%d",
256267
baseGoroutines, goroutinesWithHash, increasedHash, numWorkers, hashThreshold)

0 commit comments

Comments
 (0)