Skip to content

test(#167): watcher 那条把定长 sleep 换成轮询 —— 4.0s sleep 装在 5.0s 预算里,CI 实测已红一次 - #931

Merged
vansin merged 1 commit into
mainfrom
fix/test683-watcher-timeout
Aug 17, 2026
Merged

test(#167): watcher 那条把定长 sleep 换成轮询 —— 4.0s sleep 装在 5.0s 预算里,CI 实测已红一次#931
vansin merged 1 commit into
mainfrom
fix/test683-watcher-timeout

Conversation

@vansin

@vansin vansin commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

test(#167): 定长 sleep 换成轮询 —— 4.0s 的 sleep 装在 bun 默认 5.0s 预算里

startHub owns a live watcher timer 这一条在 CI 上红了一次:

(fail) startHub owns a live watcher timer ... [5000.57ms]
  ^ this test timed out after 5000ms.
 4 pass  1 fail   Ran 5 tests across 1 file.

它不是偶发慢,是结构上就没有余量:两处定长 Bun.sleep(800) + Bun.sleep(3_200)
合计 4.0s,而 bun 每条测试默认预算 5.0s —— 剩 1.0s 要装下两次 bun 进程启动
(bun -e import db.js 初始化 + bun run server/src/index.ts 起一个真 hub)。
本机够,CI 里(冷 bun、Docker、72 个文件排队)不够。

改动:

  1. 等事件那处改成轮询。巡检周期是 COMMHUB_DELIVERED_STALE_PATROL_MS=25,
    事件在插入后几十毫秒就该出现,3_200ms 纯粹是余量。轮询后常态快 ~60 倍,
    慢的时候等得起(上限 20s)。

  2. 等进程那处不假装在等就绪
    🔴 我第一版写的是「等到 db 文件存在」—— 而那个文件在上一步 init 里就已经
    建好了,条件恒真,等于没等。一个不是目标状态独有的等待条件,和没有等待
    是一回事,但读起来像有。
    现在这里只保留原断言的原意(子进程没有立刻崩):
    在 800ms 窗口内轮询「它是否退出了」,一退出就立刻停下,不睡满。

  3. 给这条加显式 30s 超时。它要起两个真进程,默认 5s 对它本来就不成立。
    前两处改完常态用不到这个上限;它只保证「慢」不会被报成「坏」。

waitUntil 到期时把在等什么写进异常消息 —— 定长 sleep 超时最坏的地方不是慢,
是红落在「事件没写」这条断言上,读的人会去查 watcher,而真实原因可能是 hub 还没起来。

为什么现在才暴露:这个文件从来没进过 CI,直到 #798 把 server/src 下 72 个
测试全接进去。

⚠️ 本地没跑:这条会 bun run server/src/index.ts 起一个真 hub,不在宿主机上跑。
仅做了转译检查(bun build --external '*' → Bundled 1 module,rc=0)。
判据是 CI 里的 server unit (Docker, non-root)

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

`startHub owns a live watcher timer` 这一条在 CI 上红了一次:

    (fail) startHub owns a live watcher timer ... [5000.57ms]
      ^ this test timed out after 5000ms.
     4 pass  1 fail   Ran 5 tests across 1 file.

它不是偶发慢,是**结构上就没有余量**:两处定长 `Bun.sleep(800)` + `Bun.sleep(3_200)`
合计 4.0s,而 bun 每条测试默认预算 5.0s —— 剩 1.0s 要装下两次 bun 进程启动
(`bun -e import db.js` 初始化 + `bun run server/src/index.ts` 起一个真 hub)。
本机够,CI 里(冷 bun、Docker、72 个文件排队)不够。

改动:

1. **等事件那处改成轮询**。巡检周期是 `COMMHUB_DELIVERED_STALE_PATROL_MS=25`,
   事件在插入后几十毫秒就该出现,3_200ms 纯粹是余量。轮询后常态快 ~60 倍,
   慢的时候等得起(上限 20s)。

2. **等进程那处不假装在等就绪**。
   🔴 我第一版写的是「等到 db 文件存在」—— 而那个文件在上一步 init 里就已经
   建好了,条件恒真,等于没等。**一个不是目标状态独有的等待条件,和没有等待
   是一回事,但读起来像有。** 现在这里只保留原断言的原意(子进程没有立刻崩):
   在 800ms 窗口内轮询「它是否退出了」,一退出就立刻停下,不睡满。

3. **给这条加显式 30s 超时**。它要起两个真进程,默认 5s 对它本来就不成立。
   前两处改完常态用不到这个上限;它只保证「慢」不会被报成「坏」。

`waitUntil` 到期时把**在等什么**写进异常消息 —— 定长 sleep 超时最坏的地方不是慢,
是红落在「事件没写」这条断言上,读的人会去查 watcher,而真实原因可能是 hub 还没起来。

为什么现在才暴露:这个文件**从来没进过 CI**,直到 #798 把 server/src 下 72 个
测试全接进去。

⚠️ 本地没跑:这条会 `bun run server/src/index.ts` 起一个真 hub,不在宿主机上跑。
仅做了转译检查(`bun build --external '*'` → Bundled 1 module,rc=0)。
**判据是 CI 里的 `server unit (Docker, non-root)`。**

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vansin

vansin commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

CI 全绿(12/12),server unit (Docker, non-root)executed_files=72 discovered_files=72 failed_files=0

🔴 但我不打算拿这个绿当「修好了」的证据

这条测试在 #798 上绿过、在本 PR 上绿过,只在 #800 上红过一次。再绿一次不能区分「修好了」和「这次运气好」。

我能站得住的是机制层面的,那个不需要靠运行来验:

改之前 改之后
定长 sleep 合计 4.0s(800 + 3200) ≤0.8s,且子进程一退出就提前返回
bun 单测预算 5.0s(默认) 30s(显式)
留给两次进程启动的余量 1.0s >29s

观测到的失败是 this test timed out after 5000ms —— 和这张表对得上

顺带说一个我自己当场栽的坑(留作记录)

第一版我把等待条件写成「等到 db 文件存在」。而那个文件在上一步 bun -e import db.js 里就已经建好了 —— 条件恒真,waitUntil 一进去就返回,等于没等,但读起来像有一个稳健的等待

🔴 一个不是目标状态独有的等待条件,和没有等待是同一件事 —— 区别只在于它会骗过 review。

改法不是找一个更好的就绪判据(hub 没有廉价的就绪信号,而「打了横幅」不算就绪),而是承认这里不需要等就绪:真正需要 hub 起来的是下面那条断言,而它已经改成轮询目标状态,hub 起得慢只会让它多轮询几次。这一步只保留原断言的原意 —— 子进程没有立刻崩

为什么这个文件到今天才暴露

从来没进过 CI,直到 #798server/src 下 72 个测试全接进去。

这不是一个新回归,是一个一直在那儿、没人看得见的东西。 同一批里可能还有别的 —— 这一晚 server unit 才跑了 3 次。

@vansin
vansin merged commit a0cb1e0 into main Aug 17, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant