来自 #292 的架构级评审建议。不阻塞合入,仅供参考是否有更好的架构解法。
💡 [建议 · 并发] 扫描测试用固定 sleep 等待 flush,非确定性 storage/scan_test.go / service/scan_integration_test.go
问题根因:store 层测试用 waitFlushed 轮询(正确),但 service 层测试 TestScanCoversFlushedData 用 time.Sleep(500ms) 等待后台 flush 落定。flush 是后台 goroutine 驱动的异步操作,固定 sleep 既不等待也不保证完成——在慢 CI 或慢盘上可能 flush 未完成导致扫描只看得到部分内存表数据;在快机上 500ms 纯属拖延。更糟的是它虽大概率通过,但一旦时序错位会产生偶发性 flaky,掩盖真正的回归信号。
为什么低级解法不够:把 sleep 改长一点或加轮询能提高单次通过率,但仍是「撞运气」式的同步策略,没有在测试与被测行为之间建立确定性的 happen-before。这会在 CI 上埋下间歇性失败的雷,排查成本高。
架构级方案:service 层不应直接依赖存储内部的 dirty 状态(waitFlushed 是 store 包内私有)。应在 service 层建立可观测的确定性等待点:例如暴露一个 flush 完成的 marker/水位(原子计数或等待 group),或者像 store 测试那样通过 config 的极大阈值 + 显式调用 flush 的接口来构造「已落盘」的确定状态,而非依赖后台 goroutine 的异步时序。核心原则是测试语义必须是「已 flush 才扫描」,而不是「睡了足够久」。
代价/收益:代价:需在 service 层引入一个 flush 完成的可观测点(或复用存储层同步等待钩子),API 略增。收益:消除 flaky 的根因,CI 结果可信;这正是一个静默漏数据修复的回归守护用例,若它自身都 non-deterministic,守护的意义就打折了。
💡 [建议 · 并发] 扫描测试用固定 sleep 等待 flush,非确定性
storage/scan_test.go / service/scan_integration_test.go问题根因:store 层测试用
waitFlushed轮询(正确),但 service 层测试TestScanCoversFlushedData用time.Sleep(500ms)等待后台 flush 落定。flush 是后台 goroutine 驱动的异步操作,固定 sleep 既不等待也不保证完成——在慢 CI 或慢盘上可能 flush 未完成导致扫描只看得到部分内存表数据;在快机上 500ms 纯属拖延。更糟的是它虽大概率通过,但一旦时序错位会产生偶发性 flaky,掩盖真正的回归信号。为什么低级解法不够:把 sleep 改长一点或加轮询能提高单次通过率,但仍是「撞运气」式的同步策略,没有在测试与被测行为之间建立确定性的 happen-before。这会在 CI 上埋下间歇性失败的雷,排查成本高。
架构级方案:service 层不应直接依赖存储内部的 dirty 状态(waitFlushed 是 store 包内私有)。应在 service 层建立可观测的确定性等待点:例如暴露一个 flush 完成的 marker/水位(原子计数或等待 group),或者像 store 测试那样通过 config 的极大阈值 + 显式调用 flush 的接口来构造「已落盘」的确定状态,而非依赖后台 goroutine 的异步时序。核心原则是测试语义必须是「已 flush 才扫描」,而不是「睡了足够久」。
代价/收益:代价:需在 service 层引入一个 flush 完成的可观测点(或复用存储层同步等待钩子),API 略增。收益:消除 flaky 的根因,CI 结果可信;这正是一个静默漏数据修复的回归守护用例,若它自身都 non-deterministic,守护的意义就打折了。