Node.js 输出被截断,增大 maxBuffer 仍无效
管道中输出尚未写完,生产方process.exit就可能丢失尾部。区分缓冲超限与过早退出,在实际子程序里设置退出码并完成关闭流程。
同一个 Node 命令在终端能打印完整 JSON,经 exec 或 spawn 调用后只收到前面一段;把 maxBuffer 调大也没有改善。若没有 ERR_CHILD_PROCESS_STDIO_MAXBUFFER,先检查输出数据的子程序是否调用了 process.exit。POSIX 管道中的输出可能还在异步写入,进程就被它自己结束了。
截在 8192 字节附近只是某些环境中出现的现象,不能把这个数当作 Node 输出的固定上限。Buffer.poolSize 也不是命令完整输出的容量开关。
先分清是哪一端丢了数据
检查父进程的错误码、子进程退出状态和实际收集长度,再查子程序的结束代码。如果父进程明确报缓冲超限,按maxBuffer 字节限制处理。若子进程声称正常退出、实际输出却不完整,继续查看生产方是否过早结束。
终端和管道的差异有助于定位,但不是单独的根因证明。已核对的 Node.js 24.10.0 中,POSIX 终端写入是同步的,管道及 socket 写入是异步的;Windows 的终端和管道规则不同。输出写入普通文件又有自己的同步行为,不能笼统地说 stdout 总是异步。
使用 stdio: 'inherit' 能看到完整终端输出,也不等于已经成功捕获了文本。这个选项把输出接到父进程对应的流,不能继续期待回调获得同一份收集结果。
在输出的子程序里改退出方式
问题代码可能类似下面这样。这里仅展示子程序中的顺序,payload 是它已经得到的业务结果:
process.stdout.write(JSON.stringify(payload));
process.exit(0);
process.exit 会强制结束进程,尚未完成的异步写入可能丢失。对于正常结束的命令行程序,应保留写入,让已有工作结束后自然退出:
process.stdout.write(JSON.stringify(payload));
process.exitCode = 0;
失败路径也可以设置相应的非零 exitCode,并按程序约定把诊断写到 stderr。不要为了避免截断,把业务失败改报成功。
exitCode 只决定退出时用什么状态,不会立即终止进程。程序若还持有服务器、定时器、连接等资源,需要按已有关闭流程停止新增任务、完成必要写入并释放自己持有的资源。不能只删掉 exit 后任由命令永远挂着,也不要固定 sleep 100 毫秒后再强制退出;输出大小和下游速度改变时,那个等待仍可能不够。
必须修改实际产生数据的进程。父进程多等一会儿、切换 exec 与 spawn,无法恢复子程序从未写出的字节。依赖中的 CLI 有同类问题时,核对兼容的修复版本及它的正式退出流程,不要只在调用方调缓冲。
父进程也要等到输出结束
采用 spawn 时,正常结果可能分多次 data 事件到达。只保存第一次事件,或在 exit 事件一出现就认定输出已经完整,也会造成采集缺失。应持续消费需要的 stdout、stderr,并结合 close、退出码和信号判断完成;close 在进程结束、标准流关闭后发生。
收集方案仍需要有界。输出大到不能合理缓存时,使用流式解析或受控文件处理,并处理下游失败与背压。不要为修复这一项截断又引入无界内存积累。
在隔离环境使用可核对完整性的较长输出,分别验证终端、管道和实际调用入口。检查字节数、完整 JSON 和退出状态;仅看到最后一条日志不能证明中间内容全部到达。还需覆盖失败退出及较慢的接收方。
如果命令已提交外部修改,只是结果输出丢失,不要直接重跑来补日志。先核对业务完成记录,再决定是否重试;恢复旧退出代码也不会撤销已经完成的外部操作。


