fix: 消除两处 CI flaky 根因(锁心跳空窗口 + 测试锁 Worker 泄漏) - #29
Merged
Conversation
根因:shared-core lock.test.js > 持锁方阻塞期间 Worker 心跳刷新 偶发 readToken 返回 null。旧实现 fs.ftruncateSync(fd,0) 后再 writeSync,两步之间留出空文件窗口,并发读者读到空 token 即判锁损坏(flaky 根因;覆盖率插桩放大时序窗口)。 修复: - shared-core/fs/lock.js 新增 rewriteToken(先 writeSync(offset 0) 整体覆盖、后 ftruncateSync 精确截断),读者任一时刻只读到旧/新 token,绝不为空;写后截断保证 token 变短无残留。 - Worker 心跳(lock-heartbeat.js)与主线程回退路径(startHeartbeat 的 setInterval)统一改用 rewriteToken,消除非原子 truncate→write。 - index.mjs ESM 垫片补 rewriteToken(铁律 B 防漂移)。 - 新增 2 个回归测试:调用顺序(先写后截断)+ token 变短无残留。 - 同步 3 份 vendor-shared 副本(check-vendored-shared 逐文件字节一致)。 本地验证:shared-core 178 测试通过(+2)、覆盖率 行 90.95%(门槛 90)通过、vendor-shared 一致性通过、launcher 523 测试仍全绿。
根因(launcher writeState→readState 偶发失败的真实原因):qa3-store-atomic.test.js / fix-batch3.test.js 中 acquireLock 成功后直接 releaseLock 却未传 refresh 句柄,锁心跳 Worker 线程未被停止(每 10s 仍写一次)。releaseLock 关闭 fd 后,后续测试打开文件可能复用同一 fd 号,泄漏的 Worker 把锁 token(pid\\ntimestamp\\n)写进该 fd → 覆盖 state.json 前 20 字节,readState 读到损坏 JSON → r.ok=false(非防病毒瞬态,重试无法恢复)。 修复: - 5 处 releaseLock 补传 refresh(acquireLock 返回句柄),release 后 Worker 被同步停止,杜绝 fd 复用写入。 - 重打包 release/embedded/dseam-skillmcp-0.8.1-pre.tgz(vendor-shared 锁心跳同步后的必然产物,check-embedded-tgz 一致)。 本地验证:launcher 523 测试通过、lint/depcheck 通过、check-embedded-tgz 通过。
YisfL
added a commit
that referenced
this pull request
Aug 23, 2026
按需求将代码状态回退到 cd6b9db(PR #29 合并点,版本 1.0.1),撤销其后 4 个提交: - f5d3ef6 feat(ui): 主页重设计为工业中控台 + 顶栏四分组导航 - 72a7373 build: 重编 exe/Setup 内嵌新 UI + 版本升级 1.0.3 - 0b12a5c build: 同步重建时刷新的 WebView2 运行 DLL - 7fc5e53 build: 用协作方升级的 WebView2 DLL 重编 exe/Setup force-push 被 main 分支保护拦截,故以 revert 提交实现(历史保留,树与 cd6b9db 逐字节一致)。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
合并 #27 后
mainCI 出现两处独立的 flaky 失败,均为真实竞态而非合并引入的回归(重跑即过,但根因未除会反复假阴性)。根因与修复
① shared-core 锁心跳空文件窗口(Shared Core ubuntu 覆盖率步骤偶发失败)
lock.test.js > 持锁方阻塞期间 token 仍被 Worker 心跳刷新偶发readToken返回 null。ftruncateSync(fd,0)再writeSync,两步之间留出空文件窗口,并发读者读到空 token 判损坏。rewriteToken(先writeSync(offset 0)整体覆盖、后ftruncateSync精确截断),读者任一时刻只读到旧/新 token,绝不为空;Worker 与主线程回退路径统一改用。新增 2 个回归测试 +index.mjsESM 垫片补导出。② launcher 测试锁 Worker 泄漏(Launcher Test windows-latest 偶发失败)
qa3-store-atomic.test.js > writeState 成功写入后可 readState 读回偶发r.ok=false。qa3-store-atomic.test.js/fix-batch3.test.js中acquireLock成功后直接releaseLock却未传refresh句柄,锁心跳 Worker 线程未被停止(每 10s 仍写一次)。releaseLock关闭 fd 后,后续测试打开文件可能复用同一 fd 号,泄漏的 Worker 把锁 token 写进该 fd → 覆盖state.json前 20 字节 → 读到损坏 JSON(确定性损坏,读重试无法恢复,故此前 fix: state 读路径瞬态 IO 有界重试,消除 Windows 防病毒 flaky(CI 假阴性) #28 的读重试并非此根因的解法)。releaseLock补传refresh(acquireLock返回句柄),释放后 Worker 被同步停止,杜绝 fd 复用写入。③ 内嵌 tgz 重打包
vendor/dseam-skillmcp/vendor-shared/fs/lock*.js,故release/embedded/dseam-skillmcp-0.8.1-pre.tgz同步重打包(check-embedded-tgz逐字节一致,45 文件)。验证