Node.js之进程与子进程
目录
进程(Process)
在Node.js中,process是一个全局对象,提供了当前运行进程的信息和控制能力。每个Node.js应用程序都运行在单一进程中,通过process对象可以访问和控制该进程。
进程的常用场景
- 环境配置管理:读取环境变量,根据不同环境执行不同逻辑
- 命令行工具开发:处理命令行参数,构建CLI应用
- 应用监控:监控内存使用、CPU使用率等性能指标
- 优雅退出处理:处理进程退出信号,进行资源清理
- 错误捕获:捕获未处理的异常和Promise rejection
进程中的常用属性和方法
| 属性/方法 | 作用 | 类型 |
|---|---|---|
process.pid | 获取进程ID | Number |
process.argv | 获取命令行参数数组 | Array |
process.env | 获取环境变量对象 | Object |
process.cwd() | 获取当前工作目录 | Function |
process.exit() | 终止进程 | Function |
process.memoryUsage() | 获取内存使用情况 | Function |
process.uptime() | 获取进程运行时间 | Function |
process.platform | 获取操作系统平台 | String |
示例
获取命令行参数
// 命令: node app.js --port 3000 --env production
console.log('命令行参数:', process.argv);
// 输出: ['node', '/path/to/app.js', '--port', '3000', '--env', 'production']
// 解析命令行参数
function parseArgs() {
const args = process.argv.slice(2);
const config = {};
for (let i = 0; i < args.length; i += 2) {
const key = args[i].replace('--', '');
const value = args[i + 1];
config[key] = value;
}
return config;
}
const config = parseArgs();
console.log('解析后配置:', config);
// 输出: { port: '3000', env: 'production' }
// 使用第三方库解析参数
const yargs = require('yargs');
const argv = yargs
.option('port', {
alias: 'p',
description: '服务端口号',
type: 'number',
default: 3000
})
.option('env', {
alias: 'e',
description: '运行环境',
type: 'string',
default: 'development'
})
.help()
.argv;
console.log(`服务启动在端口 ${argv.port},环境: ${argv.env}`);
读取环境变量
// 读取环境变量
console.log('数据库URL:', process.env.DATABASE_URL);
console.log('API密钥:', process.env.API_KEY);
console.log('运行环境:', process.env.NODE_ENV || 'development');
// 环境变量配置管理
class Config {
constructor() {
this.port = process.env.PORT || 3000;
this.dbUrl = process.env.DATABASE_URL || 'mongodb://localhost:27017/myapp';
this.jwtSecret = process.env.JWT_SECRET;
this.nodeEnv = process.env.NODE_ENV || 'development';
this.validate();
}
validate() {
const required = ['JWT_SECRET'];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
console.error(`缺少必需的环境变量: ${missing.join(', ')}`);
process.exit(1);
}
}
isDevelopment() {
return this.nodeEnv === 'development';
}
isProduction() {
return this.nodeEnv === 'production';
}
}
const config = new Config();
终止进程
// 优雅退出处理
class GracefulShutdown {
constructor() {
this.isShuttingDown = false;
this.connections = new Set();
this.setupSignalHandlers();
}
setupSignalHandlers() {
// 处理SIGTERM信号(Docker、Kubernetes常用)
process.on('SIGTERM', () => {
console.log('收到SIGTERM信号,开始优雅关闭...');
this.shutdown('SIGTERM');
});
// 处理SIGINT信号(Ctrl+C)
process.on('SIGINT', () => {
console.log('收到SIGINT信号,开始优雅关闭...');
this.shutdown('SIGINT');
});
// 处理未捕获异常
process.on('uncaughtException', (error) => {
console.error('未捕获的异常:', error);
this.shutdown('uncaughtException');
});
// 处理未处理的Promise rejection
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的Promise rejection:', reason);
this.shutdown('unhandledRejection');
});
}
async shutdown(signal) {
if (this.isShuttingDown) {
console.log('正在关闭中,忽略重复信号');
return;
}
this.isShuttingDown = true;
console.log(`开始优雅关闭进程 (信号: ${signal})`);
try {
// 停止接受新连接
if (this.server) {
this.server.close();
}
// 关闭现有连接
const closePromises = Array.from(this.connections).map(conn => {
return new Promise(resolve => {
conn.end(resolve);
});
});
await Promise.all(closePromises);
// 关闭数据库连接
if (this.database) {
await this.database.close();
}
console.log('优雅关闭完成');
process.exit(0);
} catch (error) {
console.error('关闭过程出错:', error);
process.exit(1);
}
}
}
// 监控进程性能
setInterval(() => {
const memUsage = process.memoryUsage();
const cpuUsage = process.cpuUsage();
console.log('进程性能监控:', {
pid: process.pid,
uptime: process.uptime(),
memory: {
rss: Math.round(memUsage.rss / 1024 / 1024) + 'MB',
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024) + 'MB',
heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024) + 'MB'
},
cpu: {
user: cpuUsage.user,
system: cpuUsage.system
}
});
}, 30000);
子进程(Child Process)
子进程是Node.js实现多进程的核心机制,允许在主进程之外创建新的进程来执行特定任务,从而避免阻塞主进程的事件循环。
子进程的使用场景
- CPU密集型计算:图像处理、数据分析、加密解密等
- 系统命令执行:文件操作、系统管理、脚本执行
- 第三方程序调用:调用Python脚本、执行外部工具
- 负载均衡:创建多个Worker进程处理请求
- 任务隔离:将不稳定任务隔离到子进程中执行
- 资源密集型任务:避免阻塞主进程的I/O操作
子进程模块的常用方法
Node.js的child_process模块提供了四个主要方法来创建子进程:
flowchart TD
A[child_process模块] --> B[exec方法]
A --> C[execFile方法]
A --> D[spawn方法]
A --> E[fork方法]
B --> B1[缓冲输出]
B --> B2[支持Shell语法]
B --> B3[内存限制]
C --> C1[直接执行文件]
C --> C2[更安全]
C --> C3[不支持Shell]
D --> D1[流式输出]
D --> D2[实时数据]
D --> D3[长时间运行]
E --> E1[Node.js专用]
E --> E2[IPC通信]
E --> E3[共享模块]
exec()方法
exec()方法创建一个Shell环境来执行命令,将输出缓冲到内存中,命令执行完毕后通过回调函数返回结果。
优点
- 简单易用:语法简洁,适合快速执行命令
- Shell支持:支持管道、重定向等Shell特性
- 自动解析:自动处理命令行参数和环境变量
缺点
- 内存限制:输出被缓冲在内存中,大量输出可能导致内存溢出
- 安全风险:通过Shell执行,存在命令注入风险
- 阻塞问题:无法实时获取输出,需要等待命令执行完毕
适用场景
- 执行简单的系统命令
- 输出量较小的命令
- 需要使用Shell特性(管道、重定向等)
- 快速原型开发和脚本编写
示例
const { exec } = require('child_process');
const util = require('util');
const execAsync = util.promisify(exec);
// 基础用法
exec('ls -la', (error, stdout, stderr) => {
if (error) {
console.error(`执行错误: ${error.message}`);
return;
}
if (stderr) {
console.error(`标准错误: ${stderr}`);
}
console.log(`输出:\n${stdout}`);
});
// 设置选项
exec('npm list --depth=0', {
cwd: '/path/to/project',
env: { ...process.env, NODE_ENV: 'production' },
maxBuffer: 1024 * 1024,
timeout: 10000
}, (error, stdout, stderr) => {
if (error) {
if (error.code === 'ETIMEDOUT') {
console.error('命令执行超时');
} else {
console.error(`执行错误: ${error.message}`);
}
return;
}
console.log('项目依赖:', stdout);
});
// 使用Promise封装
async function runCommand(command, options = {}) {
try {
const { stdout, stderr } = await execAsync(command, {
maxBuffer: 1024 * 1024,
timeout: 30000,
...options
});
if (stderr && !options.ignoreStderr) {
console.warn('警告:', stderr);
}
return stdout.trim();
} catch (error) {
throw new Error(`命令执行失败: ${error.message}`);
}
}
// 实际应用示例
async function deployApplication() {
try {
console.log('开始部署应用...');
// 拉取最新代码
await runCommand('git pull origin main');
console.log('✓ 代码更新完成');
// 安装依赖
await runCommand('npm install --production');
console.log('✓ 依赖安装完成');
// 构建应用
await runCommand('npm run build');
console.log('✓ 应用构建完成');
// 重启服务
await runCommand('pm2 restart app');
console.log('✓ 服务重启完成');
console.log('🎉 部署成功!');
} catch (error) {
console.error('❌ 部署失败:', error.message);
process.exit(1);
}
}
spawn()方法
spawn()方法创建一个子进程来执行指定程序,通过流的方式处理输入输出,适合长时间运行或大量数据处理的场景。
优点
- 流式处理:实时处理输入输出,内存使用效率高
- 实时反馈:可以实时获取命令执行过程中的输出
- 灵活控制:可以控制子进程的标准输入、输出和错误流
- 长时间运行:适合执行长时间运行的任务
缺点
- 复杂性高:需要处理多个事件和流
- 无Shell支持:不支持Shell语法特性
- 手动处理:需要手动处理参数解析和输出缓冲
适用场景
- 长时间运行的进程
- 大量数据输出的命令
- 需要实时交互的程序
- 需要精确控制输入输出的场景
示例
const { spawn } = require('child_process');
// 基础用法
const ls = spawn('ls', ['-la', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`输出: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`错误: ${data}`);
});
ls.on('close', (code) => {
console.log(`子进程退出,退出码: ${code}`);
});
// 高级用法:实时日志监控
class LogMonitor {
constructor(logFile) {
this.logFile = logFile;
this.isRunning = false;
}
start() {
if (this.isRunning) return;
this.tailProcess = spawn('tail', ['-f', this.logFile]);
this.isRunning = true;
this.tailProcess.stdout.on('data', (data) => {
const lines = data.toString().split('\n').filter(line => line.trim());
lines.forEach(line => this.processLogLine(line));
});
this.tailProcess.stderr.on('data', (data) => {
console.error(`日志监控错误: ${data}`);
});
this.tailProcess.on('close', (code) => {
console.log(`日志监控进程退出,退出码: ${code}`);
this.isRunning = false;
});
console.log(`开始监控日志文件: ${this.logFile}`);
}
processLogLine(line) {
// 解析日志行
try {
const logEntry = JSON.parse(line);
// 根据日志级别处理
switch (logEntry.level) {
case 'error':
console.error('🔴 错误日志:', logEntry.message);
this.sendAlert(logEntry);
break;
case 'warn':
console.warn('🟡 警告日志:', logEntry.message);
break;
case 'info':
console.log('🔵 信息日志:', logEntry.message);
break;
}
} catch (error) {
// 非JSON格式日志
console.log('📝 原始日志:', line);
}
}
sendAlert(logEntry) {
// 发送告警通知
console.log('🚨 发送告警通知');
}
stop() {
if (this.tailProcess && this.isRunning) {
this.tailProcess.kill('SIGTERM');
}
}
}
// 文件处理示例
function compressFiles(sourceDir, targetFile) {
return new Promise((resolve, reject) => {
const tar = spawn('tar', ['-czf', targetFile, sourceDir]);
let stderr = '';
tar.stdout.on('data', (data) => {
process.stdout.write('.');
});
tar.stderr.on('data', (data) => {
stderr += data.toString();
});
tar.on('close', (code) => {
if (code === 0) {
console.log(`\n✓ 文件压缩完成: ${targetFile}`);
resolve();
} else {
reject(new Error(`压缩失败: ${stderr}`));
}
});
tar.on('error', reject);
});
}
// 使用示例
async function backupProject() {
try {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupFile = `backup-${timestamp}.tar.gz`;
console.log('开始项目备份...');
await compressFiles('./project', backupFile);
console.log('项目备份完成');
} catch (error) {
console.error('备份失败:', error.message);
}
}
fork() 方法
fork()方法是spawn()的特殊版本,专门用于创建Node.js子进程,提供了内置的进程间通信(IPC)机制。
优点
- 进程间通信:内置IPC通道,方便父子进程通信
- Node.js专用:针对Node.js优化,共享模块缓存
- 简单通信:使用
send()和message事件进行通信 - 模块共享:子进程可以访问父进程的模块
缺点
- 仅限Node.js:只能执行Node.js脚本
- 资源消耗:创建完整的Node.js进程,资源消耗较大
- 通信限制:IPC通信有数据大小限制
适用场景
- CPU密集型Node.js任务
- 需要进程间通信的场景
- 多进程架构的Node.js应用
- 任务队列处理
示例
// 主进程 (main.js)
const { fork } = require('child_process');
const path = require('path');
class TaskManager {
constructor(maxWorkers = 4) {
this.maxWorkers = maxWorkers;
this.workers = [];
this.taskQueue = [];
this.activeTasks = new Map();
this.initWorkers();
}
initWorkers() {
for (let i = 0; i < this.maxWorkers; i++) {
this.createWorker();
}
}
createWorker() {
const worker = fork(path.join(__dirname, 'worker.js'));
worker.busy = false;
worker.id = this.workers.length;
// 监听工作进程消息
worker.on('message', (message) => {
this.handleWorkerMessage(worker, message);
});
// 监听工作进程错误
worker.on('error', (error) => {
console.error(`Worker ${worker.id} 错误:`, error);
this.restartWorker(worker);
});
// 监听工作进程退出
worker.on('exit', (code, signal) => {
console.log(`Worker ${worker.id} 退出,代码: ${code}, 信号: ${signal}`);
this.restartWorker(worker);
});
this.workers.push(worker);
console.log(`Worker ${worker.id} 已创建`);
}
handleWorkerMessage(worker, message) {
const { type, taskId, result, error, progress } = message;
switch (type) {
case 'taskComplete':
worker.busy = false;
const task = this.activeTasks.get(taskId);
if (task) {
if (error) {
task.reject(new Error(error));
} else {
task.resolve(result);
}
this.activeTasks.delete(taskId);
}
this.processQueue();
break;
case 'progress':
const progressTask = this.activeTasks.get(taskId);
if (progressTask && progressTask.onProgress) {
progressTask.onProgress(progress);
}
break;
case 'ready':
console.log(`Worker ${worker.id} 准备就绪`);
break;
}
}
executeTask(taskType, data, onProgress) {
return new Promise((resolve, reject) => {
const taskId = Date.now() + Math.random();
const task = {
id: taskId,
type: taskType,
data,
resolve,
reject,
onProgress
};
this.activeTasks.set(taskId, task);
const availableWorker = this.workers.find(w => !w.busy);
if (availableWorker) {
this.assignTask(availableWorker, task);
} else {
this.taskQueue.push(task);
}
});
}
assignTask(worker, task) {
worker.busy = true;
worker.send({
type: 'executeTask',
taskId: task.id,
taskType: task.type,
data: task.data
});
}
processQueue() {
if (this.taskQueue.length === 0) return;
const availableWorker = this.workers.find(w => !w.busy);
if (availableWorker) {
const task = this.taskQueue.shift();
this.assignTask(availableWorker, task);
}
}
restartWorker(oldWorker) {
const index = this.workers.indexOf(oldWorker);
if (index !== -1) {
this.workers.splice(index, 1);
oldWorker.kill();
}
this.createWorker();
}
shutdown() {
this.workers.forEach(worker => {
worker.kill('SIGTERM');
});
}
}
// 使用示例
const taskManager = new TaskManager(4);
async function main() {
try {
// CPU密集型任务:计算斐波那契数列
console.log('开始计算斐波那契数列...');
const fibResult = await taskManager.executeTask('fibonacci', { n: 40 });
console.log(`斐波那契结果: ${fibResult}`);
// 图像处理任务
console.log('开始图像处理任务...');
const imageResult = await taskManager.executeTask('processImage', {
imagePath: './input.jpg',
filters: ['blur', 'sharpen']
}, (progress) => {
console.log(`图像处理进度: ${progress}%`);
});
console.log('图像处理完成:', imageResult);
// 数据分析任务
console.log('开始数据分析...');
const analysisResult = await taskManager.executeTask('analyzeData', {
dataSet: Array.from({length: 1000000}, () => Math.random())
});
console.log('数据分析结果:', analysisResult);
} catch (error) {
console.error('任务执行失败:', error);
}
}
main();
// 优雅关闭
process.on('SIGINT', () => {
console.log('收到SIGINT信号,关闭任务管理器...');
taskManager.shutdown();
process.exit(0);
});
// 工作进程 (worker.js)
class Worker {
constructor() {
this.setupMessageHandler();
this.sendMessage('ready');
}
setupMessageHandler() {
process.on('message', (message) => {
this.handleMessage(message);
});
}
async handleMessage(message) {
const { type, taskId, taskType, data } = message;
if (type === 'executeTask') {
try {
const result = await this.executeTask(taskType, data, taskId);
this.sendMessage('taskComplete', taskId, result);
} catch (error) {
this.sendMessage('taskComplete', taskId, null, error.message);
}
}
}
async executeTask(taskType, data, taskId) {
switch (taskType) {
case 'fibonacci':
return this.calculateFibonacci(data.n);
case 'processImage':
return this.processImage(data, taskId);
case 'analyzeData':
return this.analyzeData(data.dataSet, taskId);
default:
throw new Error(`未知任务类型: ${taskType}`);
}
}
calculateFibonacci(n) {
if (n < 2) return n;
return this.calculateFibonacci(n - 1) + this.calculateFibonacci(n - 2);
}
async processImage(data, taskId) {
const { imagePath, filters } = data;
// 模拟图像处理过程
for (let i = 0; i < filters.length; i++) {
const filter = filters[i];
const progress = Math.round((i + 1) / filters.length * 100);
// 发送进度更新
this.sendMessage('progress', taskId, null, null, progress);
// 模拟处理时间
await new Promise(resolve => setTimeout(resolve, 1000));
console.log(`Worker ${process.pid} 应用滤镜: ${filter}`);
}
return {
outputPath: `processed_${Date.now()}.jpg`,
appliedFilters: filters,
processTime: Date.now()
};
}
async analyzeData(dataSet, taskId) {
const chunkSize = Math.floor(dataSet.length / 10);
let sum = 0;
let min = Infinity;
let max = -Infinity;
for (let i = 0; i < dataSet.length; i += chunkSize) {
const chunk = dataSet.slice(i, i + chunkSize);
for (const value of chunk) {
sum += value;
min = Math.min(min, value);
max = Math.max(max, value);
}
// 发送进度更新
const progress = Math.round((i + chunkSize) / dataSet.length * 100);
this.sendMessage('progress', taskId, null, null, progress);
}
const average = sum / dataSet.length;
const variance = dataSet.reduce((acc, val) => acc + Math.pow(val - average, 2), 0) / dataSet.length;
return {
count: dataSet.length,
sum,
average,
min,
max,
variance,
standardDeviation: Math.sqrt(variance)
};
}
sendMessage(type, taskId = null, result = null, error = null, progress = null) {
process.send({
type,
taskId,
result,
error,
progress,
workerId: process.pid
});
}
}
new Worker();
三种方法区别对比
| 特性 | exec() | spawn() | fork() |
|---|---|---|---|
| 输出处理 | 缓冲输出 | 流式输出 | 流式输出 |
| 内存使用 | 高(缓冲) | 低(流式) | 中等 |
| Shell支持 | ✅ | ❌ | ❌ |
| 实时输出 | ❌ | ✅ | ✅ |
| 进程通信 | ❌ | ❌ | ✅ |
| 执行对象 | Shell命令 | 可执行文件 | Node.js脚本 |
| 安全性 | 低 | 高 | 高 |
| 适用场景 | 简单命令 | 长时间进程 | CPU密集型任务 |
| 资源消耗 | 低 | 低 | 高 |
| 错误处理 | 回调 | 事件 | 事件+IPC |
flowchart TD
A[需要执行子进程] --> B{执行什么类型的任务?}
B -->|简单Shell命令| C[使用 exec方法]
B -->|可执行文件/长时间运行| D[使用 spawn方法]
B -->|Node.js脚本/CPU密集型| E[使用 fork方法]
C --> F{输出量大吗?}
F -->|是| G[考虑使用 spawn方法]
F -->|否| H[exec方法 适合]
D --> I{需要实时交互?}
I -->|是| J[spawn方法 最佳选择]
I -->|否| K[考虑其他方案]
E --> L{需要进程间通信?}
L -->|是| M[fork方法 最佳选择]
L -->|否| N[考虑 spawn方法]
进程和子进程区别
核心差异对比
| 维度 | 进程(Process) | 子进程(Child Process) |
|---|---|---|
| 定义 | 当前运行的Node.js实例 | 由主进程创建的新进程 |
| 数量 | 单一进程 | 可创建多个 |
| 内存空间 | 独立内存空间 | 各自独立的内存空间 |
| 生命周期 | 应用程序整个生命周期 | 可控制创建和销毁 |
| 通信方式 | 无需通信(同一进程) | IPC、标准流、文件等 |
| 资源共享 | 全局共享 | 隔离的资源空间 |
| 崩溃影响 | 整个应用崩溃 | 仅子进程崩溃,主进程可恢复 |
| 用途 | 主要业务逻辑 | 特定任务、CPU密集型计算 |
进程间关系图
flowchart TD
A[主进程 - Node.js Application] --> B[process对象]
A --> C[创建子进程]
B --> D[process.env 环境变量]
B --> E[process.argv 命令行参数]
B --> F[process.pid 进程ID]
B --> G[process.memoryUsage 内存使用]
C --> H[子进程1 - exec]
C --> I[子进程2 - spawn]
C --> J[子进程3 - fork]
H --> K[执行Shell命令]
I --> L[执行系统程序]
J --> M[执行Node.js脚本]
A -.-> N[IPC通信]
J -.-> N
A -.-> O[标准流通信]
H -.-> O
I -.-> O
使用场景决策树
flowchart TD
A[需要处理任务] --> B{任务类型?}
B -->|配置管理/环境变量| C[使用 process 对象]
B -->|CPU密集型计算| D[创建子进程]
B -->|I/O密集型操作| E[主进程处理]
C --> F[process.env, process.argv等]
E --> G[使用异步I/O操作]
D --> H{需要进程间通信?}
H -->|是| I[使用 fork方法]
H -->|否| J{执行什么程序?}
J -->|Node.js脚本| I
J -->|系统命令| K[使用 exec方法]
J -->|可执行文件| L[使用 spawn方法]
I --> M[建立IPC通道]
K --> N[获取命令输出]
L --> O[处理程序流]
进程通信最佳实践
1. 错误处理和监控
class ProcessManager {
constructor() {
this.processes = new Map();
this.setupGlobalHandlers();
}
setupGlobalHandlers() {
// 全局错误捕获
process.on('uncaughtException', (error) => {
console.error('未捕获异常:', error);
this.gracefulShutdown();
});
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的Promise rejection:', reason);
this.gracefulShutdown();
});
// 进程信号处理
['SIGTERM', 'SIGINT', 'SIGUSR2'].forEach(signal => {
process.on(signal, () => {
console.log(`收到 ${signal} 信号`);
this.gracefulShutdown();
});
});
}
createChildProcess(name, scriptPath, options = {}) {
const child = fork(scriptPath, [], {
silent: false,
...options
});
child.name = name;
child.startTime = Date.now();
child.restartCount = 0;
// 子进程事件监听
child.on('message', (msg) => {
this.handleChildMessage(child, msg);
});
child.on('error', (error) => {
console.error(`子进程 ${name} 错误:`, error);
});
child.on('exit', (code, signal) => {
console.log(`子进程 ${name} 退出,代码: ${code}`);
this.handleChildExit(child, code, signal);
});
this.processes.set(name, child);
return child;
}
handleChildMessage(child, message) {
const { type, data } = message;
switch (type) {
case 'health':
console.log(`子进程 ${child.name} 健康状态:`, data);
break;
case 'metrics':
this.recordMetrics(child.name, data);
break;
case 'error':
console.error(`子进程 ${child.name} 报告错误:`, data);
break;
}
}
handleChildExit(child, code, signal) {
if (code !== 0 && child.restartCount < 3) {
child.restartCount++;
console.log(`重启子进程 ${child.name},第 ${child.restartCount} 次`);
setTimeout(() => {
const newChild = this.createChildProcess(
child.name,
child.spawnfile,
{ env: child.env }
);
newChild.restartCount = child.restartCount;
}, 1000 * child.restartCount);
}
}
recordMetrics(processName, metrics) {
// 记录性能指标
console.log(`进程 ${processName} 指标:`, metrics);
}
async gracefulShutdown() {
console.log('开始优雅关闭所有子进程...');
const shutdownPromises = Array.from(this.processes.values()).map(child => {
return new Promise((resolve) => {
child.send({ type: 'shutdown' });
const timeout = setTimeout(() => {
child.kill('SIGKILL');
resolve();
}, 5000);
child.on('exit', () => {
clearTimeout(timeout);
resolve();
});
});
});
await Promise.all(shutdownPromises);
console.log('所有子进程已关闭');
process.exit(0);
}
}
// 使用示例
const processManager = new ProcessManager();
// 创建不同类型的子进程
processManager.createChildProcess('worker1', './cpu-worker.js');
processManager.createChildProcess('logger', './log-processor.js');
processManager.createChildProcess('monitor', './health-monitor.js');
2. 性能监控和资源管理
// 子进程性能监控
class ChildProcessMonitor {
constructor(child) {
this.child = child;
this.metrics = {
memory: [],
cpu: [],
messages: 0,
errors: 0
};
this.startMonitoring();
}
startMonitoring() {
// 定期收集性能指标
setInterval(() => {
this.child.send({ type: 'getMetrics' });
}, 5000);
this.child.on('message', (msg) => {
if (msg.type === 'metrics') {
this.recordMetrics(msg.data);
}
});
}
recordMetrics(data) {
this.metrics.memory.push(data.memory);
this.metrics.cpu.push(data.cpu);
this.metrics.messages++;
// 保持最近100个数据点
if (this.metrics.memory.length > 100) {
this.metrics.memory.shift();
this.metrics.cpu.shift();
}
// 检查资源使用告警
this.checkAlerts(data);
}
checkAlerts(data) {
// 内存使用告警
if (data.memory.rss > 500 * 1024 * 1024) { // 500MB
console.warn(`⚠️ 子进程内存使用过高: ${data.memory.rss / 1024 / 1024}MB`);
}
// CPU使用告警
if (data.cpu.percent > 80) {
console.warn(`⚠️ 子进程CPU使用率过高: ${data.cpu.percent}%`);
}
}
getStats() {
const memoryAvg = this.metrics.memory.reduce((sum, m) => sum + m.rss, 0) / this.metrics.memory.length;
const cpuAvg = this.metrics.cpu.reduce((sum, c) => sum + c.percent, 0) / this.metrics.cpu.length;
return {
averageMemory: Math.round(memoryAvg / 1024 / 1024) + 'MB',
averageCPU: Math.round(cpuAvg) + '%',
totalMessages: this.metrics.messages,
totalErrors: this.metrics.errors
};
}
}