Repository navigation
Commit 4f927aa
probe
fix(webui): 断连时流只收尾一次
上一条提交说「没有东西可修」是错的。CI 证伪了它。
## 双重收尾是真的
macOS CI 上 `finalises the stream exactly once` 报 `expected 2 to be 1`。
之前本地测出 1 是因为那个测试用 `setTimeout(250)` 等 `finally`。本地机器
快,250ms 内 `finally` 还没跑到,所以第二次 `return()` 没发生,断言看着是绿的。
CI 负载低,链路跑完了,它就露出来。
**我把这个当成了「没复现 = 不存在」**,而实际是「没复现 = 我等的那个时刻
还没到」。同一天里第三次栽在同一个地方:证据不足以支撑结论时下了结论。
## 修法:一个幂等门,两条路
`abort` listener 必须在:`next()` 永远不 settle 时,只有它能收尾那个迭代器。
`finally` 也必须在:正常走完时收尾。
两条路都会跑到,于是 `return()` 被调两次。对持有订阅的 async iterator
来说那是真实的 double-close。
let finalised = false;
const finalise = async () => {
if (finalised) return;
finalised = true;
await iterator.return?.();
};
局部 `let` 就够:listener 和 `finally` 共享这个闭包和这次调用。
## 测试改用排空微任务
`finally` 不在时钟上,它在 parked pull resolve 之后的若干次微任务跳:
abort listener → `await iterator.next()` 延续 → break → finally。跳数是确定
的,时钟不是。所以数微任务,再补一次 setImmediate(socket close 到 abort
listener 走的是宏任务队列)。
这条测试守的就是这个修复,所以它必须在不靠睡眠的情况下成立。1 parent 76cc603 commit 4f927aa
1 file changed
Lines changed: 20 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
97 | 115 | | |
98 | 116 | | |
99 | 117 | | |
| |||
111 | 129 | | |
112 | 130 | | |
113 | 131 | | |
114 | | - | |
| 132 | + | |
115 | 133 | | |
116 | 134 | | |
117 | 135 | | |
| |||
0 commit comments