05adf5da4a
PR #679 implemented the swap and falsified the note's parity premise: vitest's fake clock does not intercept node:timers/promises, so the change traded deterministic fast tests (llm-retry ~4s->~10s real sleeps, two pty teardown tests rewritten real-time, a weakened workflow grace-timer guard) for ~10 deleted lines. Moved the note proposed -> rejected with the verdict on the Status line; the frozen proposal body is kept per the rejected-lifecycle contract.
2.9 KiB
2.9 KiB
Agent Note: 用 node:timers/promises 替代手写的可取消休眠
Status: rejected — 实现(PR #679)证伪了行为等价前提:vitest 的假时钟不拦截 node:timers/promises,这次替换用确定性的快速测试换来约 10 行删除,得不偿失
English | 中文
问题
三个包(package)手写了 promise 包装的定时器,而 node:timers/promises 内置模块早已提供同等能力;其他包(dsh-llm-mock-server 的 pause()、dsh-lsp-local、dsh-acp-snapshot)已经在使用该内置模块,因此这些手写副本同时也是一处一致性缺口:
packages/llm/llm-retry/src/index.ts的cancellableDelay()(约 14 行):new Promise+setTimeout+ 手动添加/移除 abort 监听器,计时走完时 resolve 为true、被中止时 resolve 为false,仅在退避等待处消费一次。packages/workflow/workflow-workerthread/src/host.ts的sleep()(约 7 行):promise 包装、已 unref 的setTimeout,用作 dispose(资源释放)宽限的时间上界。packages/pty/pty-local/src/session.ts的delay()(约 4 行):朴素的 promise 包装setTimeout,用于轮询与拆除等待。
提案
用 import { setTimeout } from 'node:timers/promises' 替换这三处实现:
- llm-retry:
try { await setTimeout(delayMs, undefined, { signal }); /* retry */ } catch { /* abort → fail */ }。传入 signal 后,该 promise 只会以 abort 错误拒绝,已提前中止的 signal 则立即拒绝;行为完全一致,包括中止时清除定时器。按仓库的空 catch 规则,这个空catch注明其吞下的是 abort 拒绝。 - workflow-workerthread:
setTimeout(ms, undefined, { ref: false }),语义完全等价,包括不会让事件循环保持存活。 - pty-local:
import { setTimeout as delay } from 'node:timers/promises',签名完全相同,调用点无需改动。
没有专属测试固定这些辅助函数本身;各包的行为测试套件继续通过。
曾考虑的替代方案
p-timeout/p-defer一类的包。 不予采纳:内置模块恰好精确覆盖这些调用点;为一行 await 引入外部包是负收益。- 维持现状。 不予采纳,但理由较弱:成本确实很小,但仓库其他地方已经在用这一内置惯用法,而同一内置能力存在两个手写变体,就会招来第三个。
验收标准
- 这三个包都不再各自定义 promise 包装的
setTimeout辅助函数,而是都从node:timers/promises导入。 llm-retry、workflow-workerthread与pty-local的测试套件原样通过(行为等价)。
风险
基本没有风险:不涉及模型可见的输出,没有平台顾虑,也不新增依赖。llm-retry 的改写把一个返回布尔值的辅助函数变成 try/catch 控制流,这是一项局部可读性判断,由实施 PR(Pull Request)裁量。