fa-comm
Version:
314 lines (309 loc) • 13.5 kB
JavaScript
require('./proto');
const cluster = require('cluster');
const os = require('os');
const cpus = os.cpus();
const path = require('path');
const ip = require('./ip');
const port = require('./port');
const events = require('events');
const child_process = require('child_process');
const iconv = require('iconv-lite');
module.exports = {
/**
* 进程ID 16进制 表示法
*/
id: '0x000' + (process.pid * process.pid || 0).toString(16).toUpperCase(),
/**
* 进程ID 10进制 表示法
*/
pid: process.pid.toString(),
/**
* 是否调试模式
*/
debugger: process.execArgv.join('').indexOf('--inspect-brk') >= 0 || process.execArgv.join('').indexOf('--inspect') >= 0,
/**
* 休眠
*/
sleep: (ms) => { return new Promise(resolve => setTimeout(resolve, ms)) },
/**
* 启动新进程(可用作集群)
* @param {String} file 可执行文件绝对路径
* @param {Array} args 参数列表
* @param {Number} length 进程个数 (调试状态该参数无效) 默认为CPU核心数
* @param {Blean} autofork 子进程异常或退出后,是否自动重启 (调试状态、单个进程该参数无效) 默认 true
* @param {Blean} showStartInfo 是否显示新进程启动信息 默认 true
*/
start: function (file, args, length, autofork, showStartInfo) {
showStartInfo = showStartInfo != undefined ? showStartInfo : true;
if (!file)
return;
args = args || [];
length = length || cpus.length;
// console.log(('startup processes:' + length).toInfo());
autofork = autofork != undefined ? autofork : true;
const msg = `startupInfo:[processes core:${length},autofork:${autofork},file:${file},args:${args}]`;
showStartInfo && console.info(msg.toInfo());
//负载均衡调度方式
// cluster.schedulingPolicy = cluster.SCHED_NONE;
cluster.schedulingPolicy = cluster.SCHED_RR;
// worker 进程之行文件的路径
const _masterConf = {
exec: file,
args: args,
cwd: path.dirname(file),
silent: false
};
cluster.setupMaster(_masterConf);
//在主进程上建立集群工作进程
if (process.execArgv.join('').indexOf('--inspect-brk') >= 0 || process.execArgv.join('').indexOf('--inspect') >= 0) {
_spawn(file, args, {
env: {
index: 0
}
});
console.warn(('use --inspect-brk= auto fork ' + file).toWarn());
return cluster;
} else {
//正常模式
if (cluster.isMaster) {
for (let i = 0; i < length; i++) {
cluster.fork({ index: i });
}
cluster.on('fork', function (worker) {
console.info(`worker #${worker.id} is forked`.toInfo());
});
cluster.on('listening', function (worker, address) {
console.info(`worker #${worker.id} listen ${address.address || ip.local}:${address.port}`.toInfo());
});
cluster.on('online', function (worker) {
console.info(`worker #${worker.id} onlined by ${'0x000' + (worker.process.pid * worker.process.pid).toString(16).toUpperCase()}`.toInfo());
});
cluster.on('disconnect', function (worker) {
console.info(`worker #${worker.id} disconnected`.toInfo());
// if (autofork) {
// setTimeout(() => { cluster.fork(); }, 500);
// }
});
cluster.on('exit', function (worker, code, signal) {
console.info(`worker #${worker.id} exited,code=${code},signal=${signal}`.toInfo());
if (autofork) {
setTimeout(() => { cluster.fork(); }, 500);
}
});
cluster.on('setup', function (execInfo) {
// console.info(`setup`);
});
cluster.on('message', function (worker, message, handle) {
console.info(`worker #${worker.id} ${JSON.stringify(message)}`.toInfo());
});
}
return cluster;
}
},
/**
* 启动新进程(可用作集群)
* @param {String} file 可执行文件绝对路径
* @param {Array} args 参数列表
* @param {Number} length 进程个数 (调试状态该参数无效) 默认为CPU核心数
* @param {Blean} autofork 子进程异常或退出后,是否自动重启 (调试状态、单个进程该参数无效) 默认 true
* @param {Blean} showStartInfo 是否显示新进程启动信息 默认 true
*/
start_v2: function (file, args, length, autofork, showStartInfo) {
return new Promise(function (resolve, reject) {
showStartInfo = showStartInfo != undefined ? showStartInfo : true;
if (!file) {
reject('params error');
return;
}
args = args || [];
length = length || cpus.length;
// console.log(('startup processes:' + length).toInfo());
autofork = autofork != undefined ? autofork : true;
const msg = `startupInfo:[processes core:${length},autofork:${autofork},file:${file},args:${args}]`;
showStartInfo && console.info(msg.toInfo());
//负载均衡调度方式
// cluster.schedulingPolicy = cluster.SCHED_NONE;
cluster.schedulingPolicy = cluster.SCHED_RR;
// worker 进程之行文件的路径
const _masterConf = {
exec: file,
args: args,
cwd: path.dirname(file),
silent: false
};
cluster.setupMaster(_masterConf);
//在主进程上建立集群工作进程
if (process.execArgv.join('').indexOf('--inspect-brk') >= 0 || process.execArgv.join('').indexOf('--inspect') >= 0) {
_spawn(file, args, {
env: {
index: 0
}
}).then(function (proc) {
console.warn(('use --inspect-brk= auto fork ' + file).toWarn());
resolve(proc);
}).catch(function (e) {
reject(e);
});
} else {
//正常模式
if (cluster.isMaster) {
let listeningCount = 0;
for (let i = 0; i < length; i++) {
cluster.fork({ index: i });
}
cluster.on('fork', function (worker) {
console.info(`worker #${worker.id} is forked`.toInfo());
});
cluster.on('listening', function (worker, address) {
listeningCount++;
console.info(`worker #${worker.id} listen ${address.address || ip.local}:${address.port}`.toInfo());
if (listeningCount == length) {
resolve(cluster);
}
});
cluster.on('online', function (worker) {
console.info(`worker #${worker.id} onlined by ${'0x000' + (worker.process.pid * worker.process.pid).toString(16).toUpperCase()}`.toInfo());
});
cluster.on('disconnect', function (worker) {
console.info(`worker #${worker.id} disconnected`.toInfo());
// if (autofork) {
// setTimeout(() => { cluster.fork(); }, 500);
// }
});
cluster.on('exit', function (worker, code, signal) {
console.info(`worker #${worker.id} exited,code=${code},signal=${signal}`.toInfo());
if (autofork) {
setTimeout(() => { cluster.fork(); }, 500);
}
});
cluster.on('setup', function (execInfo) {
// console.info(`setup`, execInfo);
});
cluster.on('message', function (worker, message, handle) {
console.info(`worker #${worker.id} ${JSON.stringify(message)}`.toInfo());
});
}
}
});
},
/**
* 启动进程守护程序启动脚本(一般用于死循环做某件事情的脚本)
* @param {jscript} file 可执行文件绝对路径
* @param {Array} args 参数列表
* @param {Blean} showMessage 是否显示脚本输出,默认true
*/
daemons: function (jscript, args = [], options) {
const self = this;
if (!self._EventEmitter) {
self._EventEmitter = new events.EventEmitter();
}
// const options = ;
let _jscript = path.basename(jscript);
const { spawn } = require('child_process');
let node = spawn(process.execPath, [_jscript, ...args], {
cwd: path.dirname(jscript),
windowsHide: true
});
self._EventEmitter._process = node;
node.on('close', (err) => {
console.error("进程出现异常,5秒后自动启用守护,自动启动");
setTimeout(() => {
self.daemons(jscript, args);
}, 5000);
});
node.stdout.on('data', (data) => {
// console.log(data.toString());
self._EventEmitter.emit("stdout", data);
});
node.stderr.on('data', (data) => {
// console.error(data.toString());
self._EventEmitter.emit("stderr", data);
});
return self._EventEmitter;
},
/**
* 根据进程名称,获取进程编号
* @param {*} command
* @returns
*/
getProcessPid: function (command) {
const cmd = process.platform === 'win32' ? 'tasklist' : 'ps aux'
let tasklist = child_process.execSync(cmd);
tasklist = iconv.decode(tasklist, "GBK").split('\n');
let pids = [];
for (let i = 0; i < tasklist.length; i++) {
const p = tasklist[i].trim().split(/\s+/);
const pname = p[process.platform == 'win32' ? 0 : p.length - 1];
const pid = p[1];
if (pname.toLowerCase().indexOf(command) >= 0 && parseInt(pid)) {
pids.push(pid);
}
}
return pids;
}
};
const _spawn = (file, args, options) => {
let { spawn } = require('child_process');
options = options || {};
if (!options.cwd) {
options.cwd = path.dirname(file);
file = path.basename(file);
}
args = Array.from(args);
args.splice(0, 0, file);
// args.insert('inspect');
// let proc = spawn(process.execPath, args, options);
// console.info(`child process forked`.toInfo());
// proc.stdout.on('data', (data) => {
// console.info(data.toString().toInfo());
// });
// proc.stderr.on('data', (data) => {
// console.error(data.toString().toInfo());
// });
// proc.on('close', (code) => {
// console.warn(`child process exited with code ${code}`.toInfo());
// });
port.getRandomUnUsePort().then(function (_port) {
args.insert('--inspect-brk=127.0.0.1:' + _port);
let proc = spawn(process.execPath, args, options);
console.info(`child process forked`.toInfo());
proc.stdout.on('data', (data) => {
console.info(data.toString().toInfo());
});
proc.stderr.on('data', (data) => {
console.error(data.toString().toInfo());
});
proc.on('close', (code) => {
console.warn(`child process exited with code ${code}`.toInfo());
});
});
}
const _spawn_v2 = (file, args, options) => {
return new Promise(function (resolve, reject) {
let { spawn } = require('child_process');
options = options || {};
if (!options.cwd) {
options.cwd = path.dirname(file);
file = path.basename(file);
}
args = Array.from(args);
args.splice(0, 0, file);
port.getRandomUnUsePort().then(function (_port) {
args.insert('--inspect-brk=127.0.0.1:' + _port);
let proc = spawn(process.execPath, args, options);
console.info(`child process forked`.toInfo());
proc.stdout.on('data', (data) => {
console.info(data.toString().toInfo());
});
proc.stderr.on('data', (data) => {
console.error(data.toString().toInfo());
});
proc.on('close', (code) => {
console.warn(`child process exited with code ${code}`.toInfo());
});
resolve(proc);
}).catch(function (e) {
reject(e);
});
});
}