Cluster模式下子进程调试端口撞车,因各worker默认均尝试监听9229;须在fork时动态注入唯一--inspect端口(如9230+偏移),而非依赖launch.json配置或全局execArgv。

Cluster 模式下子进程调试端口为什么会自动撞车
Node.js cluster.fork() 启动的每个工作进程,默认都尝试监听 9229 —— 这不是你手动写的,而是 V8 调试器在未显式指定 --inspect 参数时的 fallback 行为。主进程和所有 worker 都抢同一个端口,必然触发 EADDRINUSE,且错误常只出现在某个 worker 启动瞬间,难以复现和定位。
launch.json 里配 port 字段根本不管用
launch.json 的 port 字段只控制 VS Code 主调试会话连接的目标端口,对 cluster 内部 fork 出的子进程完全无效。即使你把 "port": 9230 写死,worker 进程仍会按默认逻辑绑定 9229,除非你主动干预它的启动参数。
- 不要在
launch.json里依赖port解决 cluster 调试问题 - 也不要在代码里写
process.execArgv.push('--inspect=9229')—— 所有 worker 会共用这个字符串,照样冲突 - 真正有效的做法是:让每个 worker 绑定**递增的唯一端口**,例如
9230,9231,9232…
用 worker.id 动态生成 --inspect 参数
在主进程中 fork 时,给每个 worker 注入带偏移量的调试地址:
const cluster = require('cluster');
if (cluster.isMaster) {
const numCPUs = require('os').cpus().length;
for (let i = 0; i < numCPUs; i++) {
const worker = cluster.fork({
// 关键:为每个 worker 设置独立调试端口
INSPECT_PORT: 9230 + i
});
}
} else {
// worker 进程中动态注入 --inspect 参数
if (process.env.INSPECT_PORT) {
process.execArgv.push(`--inspect=127.0.0.1:${process.env.INSPECT_PORT}`);
}
require('./worker.js'); // 你的业务逻辑
}
这样每个 worker 启动时都会带自己的 --inspect,端口互不干扰。VS Code 无法自动 attach 所有 worker,但你可以手动添加多个 launch 配置,分别连 9230, 9231 等。
别忽略 worker 进程退出后的端口残留
worker 崩溃或被 kill 后,V8 调试监听器可能没释放端口,导致下次 fork 时又撞上 EADDRINUSE。这不是 cluster 特有,但多进程下概率翻倍。
- 永远不要用
kill -9或任务管理器强制结束 worker —— 它跳过 V8 清理流程 - 改用
process.kill(worker.process.pid, 'SIGTERM')并等待'exit'事件 - 在 worker 入口加优雅关闭逻辑:
process.on('SIGTERM', () => server.close()) - 开发期可加端口预检(仅限 worker):
require('net').createServer().listen(9230)失败就换下一个
cluster 调试真正的难点不在“怎么连”,而在“连上之后怎么不互相踢掉”——端口必须隔离、退出必须可控、监听地址必须显式声明,缺一不可。


















