unixTerminal: input is silently queued forever when libuv threadpool completions stop arriving (CustomWriteStream has no watchdog)
维护者通常 1 天内回复
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 52/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 冷清
- 技术栈
- electron, node.js, typescript
- 领域
- cli
调研方向
从 CustomWriteStream.write() 和 _processWriteQueue() 开始,重点关注 fs.write 完成后队列如何继续推进。运行基于 FIFO 的确定性复现,并检查 threadpool 回调停止到达时的队列行为。Done 应包含针对停滞输入的明确定义的恢复或失败信号,并由回归测试提供支持。
由索引模型根据 Issue 内容生成。
描述
Environment
- node-pty 1.1.0 (
CustomWriteStreamwrite path from #833) - Electron app (pty host runs in a utility process), macOS 15 / darwin arm64
Issue
CustomWriteStream.write() queues data and relies on the async fs.write completion callback to advance the queue:
write()only starts processing when the queue transitions 0 → 1_processWriteQueue()issues onefs.writeand continues from its callback
fs.write completes on the libuv threadpool. If the pool stops delivering completions — which we observed live in production: all 4 workers idle in pthread_cond_wait, submitted work never picked up, event loop perfectly healthy — the callback never fires, the queue head never advances, and every subsequent write() appends to the queue forever. There is no error, no timeout, and no log: from the embedder's perspective the terminal simply stops accepting input while output (event-loop reads) keeps flowing. Terminal.write() returns void, so the embedder cannot observe or mitigate this from outside.
We confirmed this mechanism while investigating Orca's long-running "terminal intermittently stops accepting input" issue (stablyai/orca#8104). In the live wedged process, _writeQueue held every lost keystroke with the first task still at offset: 0, and hot-patching write to fs.writeSync restored input instantly — the fd was fine, only the threadpool path was dead.
We're investigating the Electron/libuv threadpool wedge separately. This issue is about how node-pty behaves when it happens: input stays queued indefinitely with no error and no recovery path.
Deterministic repro
The wedge can be simulated exactly by pinning every threadpool worker with a FIFO reader-open (blocks in open() until a writer appears):
const fs = require('fs');
const pty = require('node-pty');
const { execFileSync } = require('child_process');
execFileSync('mkfifo', ['/tmp/stall.fifo']);
const p = pty.spawn('/bin/sh', ['-c', 'read line; echo "GOT:$line"'], {});
p.onData((d) => process.stdout.write(d));
setTimeout(() => {
for (let i = 0; i < 6; i++) fs.open('/tmp/stall.fifo', 'r', () => {});
setTimeout(() => {
p.write('hello\n'); // never reaches the shell
fs.stat('/tmp', () => console.log('pool alive')); // never prints
}, 300);
}, 300);
- 主要语言
- TypeScript
- 星标
- 2k
- 派生
- 341
- 平均合并
- 1 天 1 小时
- 30 天内合并 PR
- 7
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
microsoft/node-pty 的其他 Issue
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
ConPTY/TSFN exit callback aborts the process during environment teardown — fixable with NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS (same root cause as #904)可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 2/5 1-3 小时 新手友好度 76/100
microsoft/node-pty#951 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 76/100
维护者通常 1 天内回复
查看 microsoft/node-pty 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
kind/chore priority/must
难度 2/5 1-3 小时 新手友好度 82/100
sidereal-io/sidereal#380 ·
维护者通常 1 天内回复
-
Mend: dependency security vulnerability
难度 2/5 1-3 小时 新手友好度 62/100
opfab/operatorfabric-core#10653 ·
维护者通常 1 天内回复
-
backend bug size:sm
难度 2/5 1-3 小时 新手友好度 82/100
chrisbenincasa/tunarr#2237 ·
维护者通常 1 天内回复
-
documentation
难度 2/5 半天 新手友好度 69/100
Lam30ne/regulate-app#39 ·