chenshenhai / blog

个人博客,没事写写玩玩~~~
146 stars 21 forks source link

Node.js 多进程自动守护管理 #29

Open chenshenhai opened 6 years ago

chenshenhai commented 6 years ago

前言:放假在家阅读了cfork模块的源码,发现其中的进程重启管理很有意思,值得学习,模仿该功能自己写了简单的进程fork和refork的核心代码片段

主要功能

多进程启动和自动守护代码

./fork.js

const cluster = require('cluster');
const os = require('os');
const cupCount = os.cpus().length; 

module.exports = fork;

/**
 * @name {Function} frok
 * @param {Object} options 
 * - {String} exec [必填]进程文件 
 * - {Array} args [必填]进程命令参数
 * - {Boolean} silent 是否要发送输 默认false
 * - {Number} count, 进程数量 默认为CPU核数
 * - {Boolean} refork, 当work进程退出或者断开,是否需要重启, 默认是true
 */
function fork (options = {}) {
  if (cluster.isWorker) {
    return;
  }

  if( !options.exec ) {
    return;
  }

  const totalWorkerCount = options.count > 0 ? options.count : cupCount;

  let opts = {
    exec: options.exec
  }; 
  let newWorker;
  let workerCount = 0;

  // 启动主进程
  cluster.setupMaster(opts);

  for( let i=0; i<totalWorkerCount; i++ ) { 
    // 根据配置启动相关的子进程
    newWorker = forkWorker();
  }

  /**
   * @name forkWorker worker进程启动方法
   * @return {Object} 
   */
  function forkWorker() { 
    // 判断进程是否超过CPU数量
    if( workerCount >= cupCount ) {
      return;
    }
    // 如果不超过CPU数量的就fork worker进程
    workerCount ++;
    return cluster.fork();
  }

  /**
   * @name reforkWorker worker进程重启方法
   * @return {Object} 
   */
  function reforkWorker() {
    return forkWorker()
  }

  // 监听进程是否退出
  cluster.on('exit', (worker, code, signal) => { 
    console.log( `the worker pid  ${worker.process.pid} has exited` )
    // 重新fork进程
    reforkWorker();
  });

  // 监听进程是否断开连接
  cluster.on('disconnect', (worker) => { 
    console.log( `the worker pid  ${worker.process.pid} has disconnected` )
    let isDead = worker.isDead && worker.isDead();
    if ( isDead ) {
      console.log( `the worker pid  ${worker.process.pid} is dead` )
      return;
    } 
    workerCount --;
    reforkWorker();
  });

  return cluster;
}

多进程守护使用

index.js

const fork = require('./fork');

fork({
  exec: './worker'
})

worker.js

const http = require('http');
const process = require('process');

const PORT = 3001;

const server = http.createServer((req, res) => {
  res.write('hello fork');
  res.end();
});

server.listen(PORT, () => {
  console.log(`the server is start at port ${PORT}, PID=${process.pid}`)
})

测试效果

启动多进程守护

2018-02-20 3 47 53

手动删除其中的一个子进程

2018-02-20 3 48 27

可以看出当监听到子进程退出后,就会自动重启一个新的进程,保证指定数量多进程的执行

参考代码

https://github.com/node-modules/cfork/blob/master/index.js