17

I currently have an operation in a module that is blocking, so I'm looking at making this into a child process that I fork instead.

If I want to do that, then I of course need to modify the architecture of my module. The module requires that a dependency is injected by calling the module as a function, passing in the dependency, like so:

var dependency = { name: "Bob" }
require('worker')(dependency)

Then in my worker module:

module.exports = function (dependency) {
  // Outputs { name: "Bob" }
  console.log(dependency)
}

How can I turn this example into a child process being forked?

  • fork a child and then send the dependency from the parent using child.send(message). The object you pass can't be cyclic. http://nodejs.org/api/all.html#all_child_process_fork_modulepath_args_options – Gabriel Llamas Mar 12 '13 at 17:59
  • @GabrielLlamas I need to use `child.send(message)` later to actually send data to the worker (not dependencies). I don't understand how my worker can differentiate between what sort of messages it is being sent, and how to handle them. –  Mar 12 '13 at 18:03
  • well, I was doing a complete example while you accepted another answer, look at it! – Gabriel Llamas Mar 12 '13 at 18:33

3 Answers3

29

When using .fork() you are spinning up a completely separate process, so you are not able to pass around references between the parent and child processes (and are limited to messaging after the process has been created).

An approach not requiring messaging is to pass arguments (in an array) when you fork the process. Although I believe you'll have to stick with simple string/number values (but it looks like this might be enough for you from the code). Eg.:

At top level:

var name = 'bob'
var args = [name];
var childProcess = require('child_process').fork(__dirname + '/worker', args);

In the worker process:

var name = process.argv[2]; //AFIAK elements 0 and 1 are already populated with env info

Update

If you really want to go the messaging route (which I'd hesitate to recommend if you already need to send messages), then you could differentiate between the types of messages something like this (there may be more elegant ways):

At top level:

var childProcess = require('child_process').fork(__dirname + '/worker');
childProcess.send({msgtype:'dependencies', content:dependencies});

//Then to send 'normal' message:
childProcess.send({msgtype:'myothermessagetype', content:'some content'}

In worker process:

process.on('message', function(msg){
    if(msg.mtype == 'dependencies') {
       var dependencies = msg.content;
       //Do something with dependencies
    } else if(msg.mtype == 'myothermessagetype') {
       var normalmessage = msg.content;
       //Do something in response to normal message.
    }
});
UpTheCreek
  • 31,444
  • 34
  • 152
  • 221
  • Thank you for the informative answer. Unfortunately I require an object to be passed… although I guess I could stringify it. –  Mar 12 '13 at 18:14
  • 1
    Yeah, personally I'd stringify or, if it's not too complex, hack it up into it's constituents temporarily. I don't like to complicate the messaging logic with both setup and normal 'runtime' stuff. – UpTheCreek Mar 12 '13 at 18:17
  • fails when doing "node a/b/c/app.js" – Gabriel Llamas Mar 12 '13 at 18:30
  • 1
    @UpTheCreek Would you do the latter or just stringify and send as arg? –  Mar 12 '13 at 18:30
  • @GabrielLlamas - could you give more detail pls? Do you mean the reference to worker.js? (that's just an example). – UpTheCreek Mar 12 '13 at 18:32
  • @UpTheCreek I've just discovered that either stringifying or sending the object as a message will not deliver any functions. Is there any way around this? –  Mar 12 '13 at 20:02
  • Are the functions embedded in the object? Easiest thing to do is extract the functions to a library module which you would then include in both the parent and child via require(). Other option is to pass all the objects data as individual args, and then instantiate a new object (and functions) with this data in the child. Also take a look at this: http://stackoverflow.com/questions/3685703/javascript-stringify-object-including-members-of-type-function – UpTheCreek Mar 12 '13 at 21:28
  • @UpTheCreek How can we get details from mongodb in child page and send to main page to print on console. Please look at http://stackoverflow.com/questions/43490211/how-to-fetch-the-details-from-mongo-db-and-send-or-store-in-object-in-nodejs-for – charan tej Apr 19 '17 at 08:22
  • What about saving it as a json file and sending the filename as a message ? – Kush Jul 29 '20 at 14:18
2

a.js

var fork = require ("child_process").fork;
var child;
var init = false;

var m = module.exports = {};
m.init = function (o){
    if (init) return;
    init = true;
    child = fork (__dirname + "/child");
    child.send ({ init: o });
};
m.print = function (o){
    if (!init) return;
    child.send ({ msg: o });
};
m.uninit = function (){
    if (!init) return;
    child.on ("exit", function (){
        init = false;
    });
    child.kill ();
};

child.js

var dependency;

var print = function (o){
    console.log (o + dependency.name);
};

process.on ("message", function (o){
    if (o.init){
        dependency = o.init;
    }else{
        print (o.msg);
    }
});

b.js

var a = require ("./a");
a.init ({ name: "asd" });
a.print ("hi, ");
setTimeout (function (){
    a.uninit ();
}, 1000);

Prints: hi, asd

Gabriel Llamas
  • 18,244
  • 26
  • 87
  • 112
1

In the main module:

var dependency = {message: 'hello there'};
var args = [JSON.stringify(dependency)];
var child = require('child_process').fork('worker', args);
child.send('sayhello');
child.send('exit');

And in the child process module (worker.js):

var dependency = JSON.parse(process.argv[2]);
process.on('message', function(m){
    if(m == 'sayhello') console.log(dependency.message);
    else if(m == 'exit') process.exit();
});
brianmaissy
  • 394
  • 5
  • 9