multi-process

1.5.0 • Public • Published

multi-process Document / 文档

A better wrapper for nodejs official module 'cluster'. This will save your ass from the nightmares which are caused by the bad apis design of module 'cluster'. Adding multi-process feature to your nodejs application will become a pleasure.

这是一个对 nodejs 自带官方 cluster 模块的二次封装,它能将你从官方 cluster 的糟糕 API 设计当中拯救出来!让你轻松愉悦的给自己的 nodejs 应用增加多进程能力。

中文版文档点这里

Module 'cluster' sucks!

Why nodejs official module 'cluster' sucks? it's a long story, so if you are interested, feel free to give it a shot!

Why Nodejs Official Module 'cluster' Sucks?

or let's skip to multi-process directly!

multi-process Installation

npm install multi-process

or

yarn add multi-process

You should notice that multi-process module is available in nodejs only! As for versions supported, the 'cluster' module came out very early, but for the 'message' event callback function parameters concern, nodejs 6.0+ is required.

How To Use

I will rewrite the code segments in Why Nodejs Official Module 'cluster' Sucks? as comparisions, two modes provided.

There is no need to write comments at all!

Case 1:

Source Code

const multi_process = require('multi-process')

if (multi_process.current.isMaster) {

    let master = multi_process.current
    master.on('message', function(worker,obj){
        console.log('master received from worker ' + worker.id + ' :',obj)
        console.log('master send msg back to worker ' + worker.id)
        master.sendMsg2Worker('456',worker)
    })

    let worker = multi_process.createWorker()
    console.log('create worker',worker.id)
}

if (multi_process.current.isWorker) {

    let worker = multi_process.current
    console.log('worker',worker.id,'created')
    worker.on('message', function(msg){
        console.log('worker ' + worker.id + ' received:',msg)
    })

    worker.sendMsg2Master('123')
}

Case 2: here is another mode even better

Source Code

const multi_process = require('multi-process')

multi_process.onMasterRun(function(master) {

    master.on('message', function(worker,obj){
        console.log('master received from worker ' + worker.id + ' :',obj)
        console.log('master send msg back to worker ' + worker.id)
        master.sendMsg2Worker('456',worker)
    })

    let worker = multi_process.createWorker()
    console.log('create worker',worker.id)
})

multi_process.onWorkerRun(function(worker){

    console.log('worker', worker.id, 'created')
    worker.on('message', function(msg){
        console.log('worker ' + worker.id + ' received:',msg)
    })

    worker.sendMsg2Master('123')
})

As you can see, the only thing i did is to make codes more logical and more semantic. Hope you will enjoy it.

A Real World Usage - Fibonacci Runner

Case 1: single-process mode runner

Source Code

const cpus = require('os').cpus().length
const fibonacci = require ('fibonacci')

let start = new Date().getTime()
for (let i=0; i<cpus; i++) {
    fibonacci.iterate(10000)
}
let stop = new Date().getTime()
console.log('single-process mode time cost',(stop-start),'ms')

Result: about 60s

Case 2: multi-process mode runner

Source Code

const cpus = require('os').cpus().length
const fibonacci = require ('fibonacci')
const multi_process = require('multi-process')

multi_process.onMasterRun(function(master){
    let start = new Date().getTime()
    let stop = 0
    let done = 0
    master.on('message', function(worker,obj){
        if (obj === 'done') done++
        if (done === cpus) {
            stop = new Date().getTime()
            console.log('multi-process mode time cost', (stop-start), 'ms')
            process.exit()
        }
    })
    start = new Date().getTime()
    for (let  i = 0; i < cpus; i++) { 
        multi_process.fork()
    }
})

multi_process.onWorkerRun(function(worker){
    worker.on('message', function(msg){
        console.log('worker ' + worker.id + ' received:',msg)
    })
    fibonacci.iterate(10000)
    worker.sendMsg2Master('done')
})

Result: about 25s, A good performance improvement!

My APIS

First of all, you should know i didn't change the original 'cluster' too much!

I only added some properties, some methods, some references, just to make the whole thing looks more semantic and more intuitive.

Here is something you should know about, this will help you to understand multi-process!

To solve the semanticization problems, i first analyzed the original 'cluster' module APIs and classify them, after that i created 3 classes, Class MultiProcess, Class MasterProcess and Class WorkerProcess by reassigning proper APIs to proper class, finally we have 3 brand new classes with semantic and intuitive APIs.

When you execute require('multi-process') in your code, you actually get an instance of Class MultiProcess, which should be considered as a multiple process manager. Property MultiProcess.current is a reference to the process you are running, it may be either a master process or a worker process, in either case, i will wrap the current process to an instance of MasterProcess or WorkerProcess based on it's type, and then refer MultiProcess.current to this instance. From now on we can do almost anything by operating MultiProcess.current only.

Class MultiProcess

  • #### Properties

  • #### Methods

    • createWorker() - the same as cluster.fork() - create a new worker process
    • setupProcess() - the same as cluster.setupMaster()
    • disconnect() - the same as cluster.disconnect() - this will force each worker process to disconnect to master process
    • killWorker(id[,signal]) - kill a worker process by id
    • onMasterRun(callback) - register a handler to master process when it is ready
      • callback(master) - Function - the handler function you want to run
        • master - the master process instance you get
    • onWorkerRun(callback) - register a handler to worker process when it is ready
      • callback(worker) - Function - the handler function you want to run
        • worker - the worker process instance you get
  • #### Events

    • on('create',(worker)=>{}) - the manager begin to fork a new worker process
      • worker - cluster.Worker - the new worker process instance you create
    • on('setup',(settings)=>{}) - the manager setup the process
    • on('disconnect',()=>{}) - all worker processes disconnected

Class MasterProcess

  • #### Properties

    • id - Null - here you get null
    • isMaster - Boolean - here you get true of course
    • isWorker - Boolean - here you get false of course
  • #### Methods

    • sendMsg2Worker(msg,worker) - send a message to worker process
      • msg - Object - the message content you want to send
      • worker - cluster.Worker - the worker process you want to send message to
      • returns - Boolean
  • #### Events

    • on('message',(worker,msg)=>{}) - master process get a message
      • worker - cluster.Worker - the worker process who send you this message
      • msg - Object - message content

Class WorkerProcess

  • #### Properties

    • id - Number - the worker process id
    • isMaster - Boolean - here you get false of course
    • isWorker - Boolean - here you get true of course
    • process - ChildProcess - the same as worker.process
  • #### Methods

    • disconnect() - the same as worker.disconnect() - this worker process will disconnect itself from master process
    • isConnected() - the same as worker.isConnected() - return whether this worker is connected to master process
      • returns - Boolean
    • isDead() - the same as worker.isDead() - return whether this worker has terminated
      • returns - Boolean
    • suicide() - the same as worker.kill() - the worker process kill iteself
    • sendMsg2Master(msg) - send a message to master process
      • msg - Object - the message content you want to send
      • returns - Boolean
  • #### Events

    • on('online',()=>{}) - the worker process is ready
    • on('listening',(address)=>{}) - the worker process begin to listen, this is only available in net-related modules
    • on('message',(msg)=>{}) - worker process get a message
      • msg - Object - message content
    • on('error',(err)=>{}) - a process-fork-related error jumps out
      • err - Error - the error caught
    • on('disconnect',()=>{}) - worker processes disconnected from master process
    • on('exit',(code,signal)=>{}) - the worker process dies
      • code - Number - the exit code
      • signal - String - the name of the signal that caused the process to be exited

Examples

I provided several examples to explain every thing about this module, you can find them in my github repostry.

Source Code

  • examples
    • officialCluster1.js - how the official cluster module works in cluster-bind mode
    • officialCluster2.js - how the official cluster module works in worker-bind mode
    • multiProcess1.js - how the multi-process module works in normal mode
    • multiProcess2.js - how the multi-process module works in registeration mode
    • fibonacci1.js - how to run a fibonacci runner in single-process mode
    • fibonacci1.js - how to run a fibonacci runner in multi-process mode

Hope it is helpful to you guys !

Readme

Keywords

Package Sidebar

Install

npm i multi-process

Weekly Downloads

0

Version

1.5.0

License

MIT

Unpacked Size

39.6 kB

Total Files

14

Last publish

Collaborators

  • dinsio