23 process、child_process 与 cluster Cheatsheet
process 高频属性与方法
| API | 作用 | 注意事项 |
|---|---|---|
process.pid |
当前 PID | 每个 Cluster Worker 不同 |
process.ppid |
父 PID | 容器/进程管理器下需结合进程树 |
process.argv |
命令行参数 | 前两项通常是 Node 和脚本路径 |
process.execArgv |
Node 启动选项 | 不等于业务参数 |
process.env |
环境变量 | 值是字符串或 undefined;不要完整打印 |
process.cwd() |
当前工作目录 | 相对路径以此为基准 |
process.chdir() |
改变 cwd | 服务中慎用,会影响整个进程 |
process.exitCode |
设置自然退出码 | 通常优于立即 exit() |
process.exit() |
立即进入退出流程 | 可能截断异步日志/stdout |
process.memoryUsage() |
内存指标 | RSS、Heap、External 含义不同 |
process.cpuUsage() |
CPU 微秒统计 | 不是直接的百分比 |
process.uptime() |
运行秒数 | 可用于诊断 |
process.kill(pid, signal) |
给 PID 发送 Signal | 名称不代表一定“杀死” |
标准流
stdin fd 0,Readable
stdout fd 1,Writable
stderr fd 2,Writable
stdio 三者及额外通道的统称/配置
process.stdin.pipe(process.stdout);
process.stderr.write("diagnostic\n");
Bash:
command > stdout.log
command 2> stderr.log
command > all.log 2>&1
producer | consumer
记住:stderr 有输出不等于进程失败,成功通常由退出码和业务协议共同决定。
Process 事件与 Signal
| 事件 | 用途 | 注意事项 |
|---|---|---|
SIGINT |
Ctrl+C 等中断 | Windows/终端行为存在差异 |
SIGTERM |
PM2/systemd/容器停机 | 做优雅关闭 |
beforeExit |
事件循环将为空 | 不是通用停机钩子 |
exit |
即将退出 | 只能可靠执行同步代码 |
warning |
Node.js 警告 | 例如监听器过多 |
uncaughtException |
未捕获异常 | 进程状态可能不可靠,应清理后退出 |
unhandledRejection |
未处理 Promise 拒绝 | 不应仅记录后继续假装健康 |
child_process 选择
| API | Shell | 输出 | 推荐场景 |
|---|---|---|---|
spawn() |
默认否 | Stream | 长任务、大输出、实时进度 |
exec() |
是 | 缓冲后回调/Promise | 可信、短小 Shell 命令 |
execFile() |
默认否 | 缓冲后回调/Promise | 明确可执行文件、小输出 |
fork() |
启动 Node.js | Stream + IPC | Node.js 子任务 |
*Sync() |
视 API | 阻塞返回 | CLI/启动阶段,Express 中避免 |
默认优先:
spawn(executable, args, {
shell: false,
});
ChildProcess 常用属性
| 属性 | 含义 | 易错点 |
|---|---|---|
pid |
子进程 PID | 启动失败时可能不可用 |
stdin |
子进程标准输入 | stdio 非 pipe 时可能为 null |
stdout |
子进程标准输出 | 必须消费或明确 inherit/ignore |
stderr |
子进程标准错误 | 有内容不等于失败 |
exitCode |
已退出时的码 | 运行中通常为 null |
signalCode |
终止 Signal | 被 Signal 终止时使用 |
killed |
是否成功发送过终止请求 | 不代表进程已经退出 |
connected |
IPC 是否连接 | 不代表业务健康 |
ChildProcess 事件
| 事件 | 含义 | 使用建议 |
|---|---|---|
spawn |
成功创建子进程 | 仅表示启动阶段成功 |
error |
启动/发送等失败 | 命令不存在通常在这里 |
exit |
子进程已退出 | stdio 可能尚未全部关闭 |
close |
进程结束且 stdio 关闭 | 常用于最终 settle |
message |
IPC 消息 | 必须运行时校验 |
disconnect |
IPC 断开 | 不等于进程必然退出 |
常见时间线:
启动失败:error → close
正常:spawn → data... → exit(0) → close(0)
业务失败:spawn → data... → exit(non-zero) → close(non-zero)
Signal:spawn → exit(null, signal) → close(null, signal)
事件的精确组合还受平台、stdio 和 API 调用影响,封装必须避免 Promise 重复 settle。
stdio 配置
stdio: "pipe" // 父进程可访问 child.stdin/out/err
stdio: "inherit" // 直接继承父终端
stdio: "ignore" // 丢弃
stdio: ["pipe", "pipe", "pipe", "ipc"]
数组索引:
0 stdin
1 stdout
2 stderr
3+ 额外 fd/IPC
超时和取消
const controller = new AbortController();
const child = spawn(command, args, {
signal: controller.signal,
});
controller.abort();
取消后仍需要:
处理 AbortError/error
等待 close
确认进程树策略
清理半成品
更新任务状态
IPC
fork():
child.send({
type: "start",
taskId,
});
child.on("message", (message: unknown) => {
// 运行时校验
});
不能发送并共享:
普通函数
Express Request
Sequelize 连接
EventEmitter 实例状态
任意巨大对象而不考虑复制成本
Cluster 高频 API
| API | 作用 |
|---|---|
cluster.isPrimary |
当前是否 Primary |
cluster.isWorker |
当前是否 Worker |
cluster.fork() |
创建 Worker 进程 |
cluster.workers |
Worker 映射 |
cluster.worker |
当前 Worker 信息 |
cluster.setupPrimary() |
配置 Worker 启动参数 |
cluster.disconnect() |
断开 Worker 并等待关闭 |
worker.send() |
Primary 向 Worker 发 IPC |
worker.kill() |
终止 Worker |
Cluster 事件:
fork
online
listening
message
disconnect
exit
技术选择
调用 Python/R/Bash spawn()/execFile()
运行 Node.js 子任务 + IPC fork()
CPU 密集 JavaScript worker_threads
多进程共享 Express 端口 cluster 或 PM2 cluster mode
可靠后台任务 BullMQ/任务系统 + Worker
跨机器通信 Redis/消息队列/数据库
Cluster 上线检查
[ ] 每个 Worker 都会执行入口文件
[ ] 定时任务/迁移没有重复运行
[ ] 内存 Session、Map、限流不被误认为共享
[ ] 数据库总连接数已乘 Worker 数量
[ ] 日志包含 PID/Worker ID
[ ] Worker 崩溃重启有退避和上限
[ ] SIGTERM 能优雅关闭 Server 和子进程
[ ] WebSocket/长连接策略明确
[ ] PM2 没有与代码 Cluster 双重扩容
子进程上线检查
[ ] executable 来自白名单配置
[ ] args 使用数组,没有拼接 Shell
[ ] cwd 与 env 明确
[ ] stdout/stderr 有界消费
[ ] Chunk 按流处理,不假设是一行
[ ] error 与 close 都处理
[ ] 非零退出、Signal、结果缺失均能识别
[ ] timeout/abort 后等待实际退出
[ ] 孙进程/进程树策略经过目标平台测试
[ ] 临时结果失败后清理
[ ] 日志不含秘密和敏感数据