0

I have reqirement where I need to execute some code written in different js file. I am using fork method in child_process module. There will be upto 1000 request to execute that file code in single API call. With that much request it becomes important to kill that process that is executing the child file.

My queries are:

  1. Are the child process generated from fork method kill themselves after executing code or do we have to kill them explicitly(if yes, how can we achieve that)

There are many question and answers are available in forking and childprocess but none are available for NodeJS, I couldn't get any help from following those answers.

With my limited knowledge I wrote the sample code and tried to kill the process running in child node. That works fine for 1st API request, but when 2nd API request comes. Node applicatin collapses.

My Codes:

master.js

const fork = require('child_process').fork;
const cp1 = fork('./child1.js');

const app = require('express')();

function timer(ms) {
   return new Promise(resolve => setTimeout(resolve, ms));
 }

app.get('/forktesting',(req, res)=>{
   let num = [45, 5, 48, 91, 74, 3, 82];
   try {
      for (let index = 0; index < num.length; index++) {
         await timer(1000);
         cp1.send('test');
   }
   cp1.on('message', (msg)=>{
      console.log(`recieving message code in parent process: ${msg.val}`);
   });
   cp1.on('exit',(msg=>{
      console.log(`recieving exit code in parent process: ${msg}`);
   }));
   console.log('last line of API call');
} catch (error) {
      console.log({'error' : error});
      res.send({"code": 500, "status":"error"});
   }
});

app.listen(8081, ()=>{ console.log(`listening to 8081`);})

child1.js

process.on('message', async(message)=>{
    console.log(`in message child: ${message}`);
    setTimeout(() => {
        process.send({ val: "from child"});
        console.log(`child pid: ${process.pid}`);
        process.kill(process.pid);
    }, 5000);
})

Response in 1st API call which is working fine Respone from 1st API call

Error Upon calling API 2nd time

Note: Showing correct implementation would be very helpful

In the second file(child1.js), I am calling differen system and waiting the response from them, upon receving the response I will send it to the parent process.

Edit2: Added for loop around cp1.send() to show that with single API call there will be multiple forking of the child process and added try catch block. I have added for loop for forking as required by the actual scenario. so same file will be forked many times, I have shown 3 items in array but that would be 1000 later, which would be fetced from DB. The scenario is: with every API call, I have to fork multiple times, and that API would be frequented by users, so multiple users will be accessing it. With Every API hit, the listeners will be added, so single response will be heard my many listerners, that would also create problem after some threshold of listeners count will cross. So, implementation of event.once would be good, but I want the child response count also so probably have to go with on listener to listen response of every forked child.

Edit1: I removed the process.kill(process.pid) in child process and hit twice within the 5 secs. I am getting twice response, that's not the functionality I desire. Below picture showing the console output.

response when API hit twice with process.kill(process.pid) removed

I should get only one response only from that forked process. With the remove process.kill(process.pid), every call to this API is increasing the response count.

Photos shows logs for original question and edit 1

gs1208
  • 73
  • 5
  • 9
  • You don't want to kill any of these processes. You want to `exit` the child process when it's done. – Bergi Nov 28 '20 at 21:34
  • You are forking the process only once when the server starts, not once per request. Since your child process stops after being killed by the first request, it won't be available for the second request any more. Not sure what you are actually trying to achieve – Bergi Nov 28 '20 at 21:36
  • "*Are the child process generated from fork method kill themselves after executing code*" - yes, every process stops (exits) by itself when it is done, i.e. when it thinks it's done by itself. (Which might be never, of course). – Bergi Nov 28 '20 at 21:38
  • @Bergi, I have added for loop as the actual scneario requires, please see the edited question. When I am exiting the child process, the other API call is crashing the node proces, I tried disconnect method also but same issue of crashing is occuring. Please refer this also, it is stating otherwise: [https://stackoverflow.com/questions/39523422/node-child-process-will-it-always-terminate-by-itself] – gs1208 Nov 29 '20 at 13:26
  • 1
    "*with single API call there will be multiple forking of the child process*" - no, that's still not happening. You fork the child process exactly once when the server starts, then you send (multiple) messages to it whenever your server receives a request. There's still only just one child process, not multiple forks, and no need to kill anything. – Bergi Nov 29 '20 at 13:36
  • 1
    "*[this](https://stackoverflow.com/questions/39523422/node-child-process-will-it-always-terminate-by-itself) is stating otherwise*" - no, it's saying exactly the same as I. A process stops either when it is killed or when it decides to exit on its own, which most - but not all - processes do. In any case, you control the child process, so first you need to *decide* when it should exit. You still haven't told us what the child process is *supposed* to do, other than "*I am calling differen system and waiting the response from them*", but that doesn't necessitate a child process by itself. – Bergi Nov 29 '20 at 13:38
  • @Bergi, Child process will connect with one system which will connect other system and this other system will schedule the jobs in the database and as soon as the other system intiate the scheduling in DB, it will give us some response of scheduling started via same path. We have decided to put in the child process beacuse it may cause blocking issue in the main thread, the one system that we are connecting with are having JCO connector issue (some session issue) if called from main thread, if put the connecting part in child process, we are not facing much issue with JCO connector. – gs1208 Nov 29 '20 at 13:51

2 Answers2

1

In child1.js you want to use:

process.on('message', async(message)=>{
    console.log(`in message child: ${message}`);
    setTimeout(() => {
        process.send({ val: "from child"});
        console.log(`child pid: ${process.pid}`);
        process.exit();
    }, 5000);
})

The big difference is using process.exit(); for the child to terminate itself. It will return an integer passed in process.exit(); (default is 0).

Also change your master.js to:

const fork = require('child_process').fork;
var cp1 = fork('child1.js');

const app = require('express')();

app.get('/forktesting',(req, res)=>{
  cp1 = fork('child1.js');
   cp1.send('test');
   cp1.on('message', (msg)=>{
      console.log(`recieving message code in parent process: ${msg.val}`);
   });
   cp1.on('exit',(msg)=>{
      console.log(`recieving exit code in parent process: ${msg}`);
   });
   console.log('last line of API call');
});

app.listen(8081, ()=>{ console.log(`listening to 8081`);})

When you originally spawn a child process with: var cp1 = fork('child1.js'); it then terminates itself, so you have to spawn another child process with cp1 = fork('child1.js'); the next time a user or program needs it.

Also to answer your question, child processes don't terminate on their own, you have to tell it to terminate, similar question here.

NO_GUI
  • 444
  • 8
  • 12
  • I did not get you, please enlighten. I replaced `process.kill(process.pid) ` with `process.exit()` , error was thrown 'The "pid" argument must be of type number. Received type undefined'. When I replaced `process.kill(process.pid)` with `process.exit(0)`, I am facing the same previous issue when API was hit twice. – gs1208 Nov 28 '20 at 17:47
  • Ok I figured it out, I'll edit my answer now. – NO_GUI Nov 28 '20 at 19:56
0

If you make the second call within the 5 seconds timeout before you kill the process it will work. You problem is that you kill the process and try to call it afterwards. If you look at your console, you will see that the exit event is called.

Remove the

process.kill(process.pid);

and it should work. i.e

process.on('message', async(message)=>{
    console.log(`in message child: ${message}`);
    setTimeout(() => {
        process.send({ val: "from child"});
        console.log(`child pid: ${process.pid}`);
        // process.kill(process.pid); // terminates the process. Cannot use it after terminated.
    }, 5000);
})

I don't know what you are trying to achieve.

const cp1 = fork('./child1.js');

within the api it should call the script for each request.

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


const app = require('express')();

app.get('/forktesting',(req, res)=>{
    const cp1 = fork('./child1.js'); // fork for each request.
   cp1.send('test');
   cp1.on('message', (msg)=>{
      console.log(`recieving message code in parent process: ${msg.val}`);
   });
   cp1.on('exit',(msg=>{
      console.log(`recieving exit code in parent process: ${msg}`);
   }));
   console.log('last line of API call');
});

app.listen(8081, ()=>{ console.log(`listening to 8081`);})

This will create a new process for each request.

If you do create a new process for each request then do not remove the process termination in settimeout. i.e keep

process.kill(process.pid);

Have a look at https://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options for more information.

kg99
  • 746
  • 2
  • 14
  • That did not work, I implement your suggestions. I have edited question to show your implementation and its effect in the output – gs1208 Nov 29 '20 at 10:46
  • If you need to fork for each request multiple times then put const cp1 = fork('./child1.js'); in you loop – kg99 Nov 29 '20 at 14:09