How to fork a child process that listens on a different debug port than the parent - node.js

I am trying to use child_process.fork to spawn a process that breaks and listens on the V8 debug protocol.
However, I can't get the forked process to listen on a port that's different from the parent process. Assuming the parent process listens on 6000, the child process also attempts to listen on port 6000:
Failed to open socket on port 6000, waiting 1000 ms before retrying
Here's my code:
// `test.js`, invoked as `node --debug-brk=6000 test.js`
var nodeModule, args, env, child
nodeModule = path.normalize(path.join(__dirname, '..', 'app.js'))
args = [
'--debug-brk=6001'
, '127.0.0.1'
, 3030
, 'api-testing'
]
env = { 'DB_URI': 'mongodb://localhost/test' }
child = require('child_process')
.fork(nodeModule, args, {env: env})
.on('message', callback)
As you can see, I'm trying to get the forked process to listen on port 6001, but the child process attempts to listen on port 6000 which is in use by the parent.
How can I get the child process to listen on port 6001, or some other free port?
There are several threads on this subject. For example:
How to debug Node.JS child forked process?
Debugging Node.js processes with cluster.fork()
However:
These threads deal with the cluster variant of forking
Refer to execArgv, which appear to have been undocumented for process and are still undocumented for cluster.

Simple enough answer, found on this comment and with some help from #Node.js on Freenode:
Just move the --debug-brk into the execArgv key of the options param to fork:
// Excerpt:
args = [
'127.0.0.1'
, 3030
, 'api-testing'
]
env = { 'DB_URI': 'mongodb://localhost/test' }
child = fork(nodeModule, args, {
env: env
, execArgv: ['--debug-brk=6001']
})
.on('message', this.callback)
execArgv is the array of parameters passed to the node process. argv is the set passed to the main module. There's a dedicated parameter to child_process.fork for argv, but execArgvs have to be placed within the opts param. This works, and in the child process we have:
> process.execArgv
["--debug-brk=6001"]
> process.argv
["/usr/local/Cellar/node/0.10.13/bin/node" "/Users/dmitry/dev/linksmotif/app.js", "127.0.0.1", "3030", "api-testing"]
In summary
Node.js consistently treats execArgv and argv as separate sets of values.

Before to fork remove old debug-brk parameter :
process.execArgv = process.execArgv.filter(function(o){
var x = "--debug-brk";
return o.substring(0, x.length) !== x
});
and add a new one:
process.execArgv.push("--debug-brk=9999");

Related

nodejs how to find the process id

I have a nodejs application running on a live server. I start a new node process using the following command in Terminal of VSCODE by accessing the server through SSH.
nohup node filename.js &
Mostly I can see the process id using the following command in the VSCODE terminal.
netstat -lpn | grep 30001
This command gives the following output:
tcp6 0 0 :::30001 :::* LISTEN 21552/node
But, sometimes it doesnt show up any process id, as shown in the following output:
tcp6 0 0 :::30001 :::* LISTEN -
In case the process dies to due some technical error, it should get restarted automatically. I have executed the following code through a cron in every 5 minutes for this, which works.
const find = require('find-process');
var spawn = require('child_process').spawn;
find("port", "30001")
.then((list)=> {
console.log("list::", list);
if (!list.length) {
spawn('node', [`${__dirname}/filename.js`], {
detached: true,
stdio: 'ignore'
}).unref();
}
}, function (err) {
console.log(err.stack || err);
});
Following is my cron
*/5 * * * * node path-to-js-file/crontab.js
My Question:
Why my node instance on port 30001 is sometimes not having a pid while the application contained inside it is still accessible?
kill -9 will need a Process Id which I dont have as showed above. How to kill such process through command so that it can be restarted?
To show the proccess pid you can use the process module of nodejs.
var process = require('process');
console.log(`Process pid ${process.pid}`);

Node Spawn process outliving the main node process

I want to start a process that will live on its own and continue to live even if the node application that started it dies.
To do so I am trying to use child_process and I did not manage to have the process live even if the node process die.
Here is my code:
const cp = require('child_process');
const process = cp.spawn('long_running_process', ['arg1'], {
stdio: 'ignore',
detached: true
});
process.unref();
This code follows the child_process documentation available here :
https://nodejs.org/api/child_process.html#child_process_options_detached

NodeJs execute command in background and forget

I have an endless NodeJS script.js loop and I need this script to execute another script in background as a service which is a WebSocket service actually.
var exec = require('child_process').exec;
exec('node bgService.js &');
So now both scripts are running okay!
When I do a Ctrl+C on my script.js, the bgService.js script is also removed from memory which I don't want to.
How to run something in the background and forget ?
You can do it using child_process.spawn with detached option:
var spawn = require('child_process').spawn;
spawn('node', ['bgService.js'], {
detached: true
});
It will make child process the leader of a new process group, so it'll continue running after parent process will exit.
But by default parent process will wait for the detached child to exit, and it'll also listen for its stdio. To completely detach child process from the parent you should:
detach child's stdio from the parent process, piping it to some file or to /dev/null
remove child process from the parent event loop reference count using unref() method
Here is an example of doing it:
var spawn = require('child_process').spawn;
spawn('node', ['bgService.js'], {
stdio: 'ignore', // piping all stdio to /dev/null
detached: true
}).unref();
If you don't want to loose child's stdin output, you may pipe it to some log file:
var fs = require('fs'),
spawn = require('child_process').spawn,
out = fs.openSync('./out.log', 'a'),
err = fs.openSync('./out.log', 'a');
spawn('node', ['bgService.js'], {
stdio: [ 'ignore', out, err ], // piping stdout and stderr to out.log
detached: true
}).unref();
For more information see child_process.spawn documentation
Short answer: (tl;dr)
spawn('command', ['arg', ...],
{ stdio: 'ignore', detached: true }).unref()
unref is required to prevent parent from waiting.
docs

How to release resources from processes killed by grunt-contrib-watch?

I'm trying to use the module grunt-contrib-watch to restart my node.js server whenever certain files change. I already use grunt to run the server, jshint, and the template compiler, and I know those functions work. Here's the task to start the server:
grunt.registerTask('runServer', 'Starts the server.', function(){
grunt.log.writeln('Starting server...');
var done = this.async();
var child = grunt.util.spawn({
cmd: process.argv[0],
args: ['server.js'],
}, function(){
grunt.log.writeln('Server stopped!');
done(true);
});
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
});
Here's the config for the watch task:
watch: {
all: {
files: ['some/files/*.js'],
tasks: ['default'],
options: {
spawn: true,
interrupt: true,
reload: true,
}
}
}
When the task is restarted, the server fails because of an "EADDRINUSE" exception, which I take to mean is because the previous child process didn't release the port it was using, which is strange - I do see the "Server stopped!" message. I have tried this with all combinations of the three options, and I looked on the github page for grunt-contrib-watch, and nothing showed anything. How can I make the interrupted node.js process close all its resources before the next one tries to start?
Is it necessary to perform a child process spawn? In every case that I have spun up a server, I have simply done something like this:
grunt.registerTask('runServer', 'Starts the server.', require('./server'));
The watch task remains the same as you have it listed. Grunt automatically kills the previous run of that task as long as it is not a child process. This seems to work just fine for me.
However, if you NEED to spawn a child process and then kill it:
var spawn = require('child_process').spawn,
server = undefined;
...
grunt.registerTask('runServer', 'Starts the server.', function(){
grunt.log.writeln('Starting server...');
if (server)
server.kill('SIGUSR2');
server = spawn('node', ['server.js'], {stdio: 'inherit'});
}
...
grunt.registerTask('default', ['runServer']);

How to debug Node.JS child forked process?

I'm trying to debug the child Node.JS process created using:
var child = require('child_process');
child .fork(__dirname + '/task.js');
The problem is that when running in IntelliJ/WebStorm both parent and child process start on the same port.
debugger listening on port 40893
debugger listening on port 40893
So it only debugs the parent process.
Is there any way to set IntelliJ to debug the child process or force it to start on a different port so I can connect it in Remote debug?
Yes. You have to spawn your process in a new port. There is a workaround to debug with clusters, in the same way you can do:
Start your app with the --debug command and then:
var child = require('child_process');
var debug = typeof v8debug === 'object';
if (debug) {
//Set an unused port number.
process.execArgv.push('--debug=' + (40894));
}
child.fork(__dirname + '/task.js');
debugger listening on port 40894
It is a known bug in node.js that has been recently fixed (although not backported to v0.10).
See this issue for more details: https://github.com/joyent/node/issues/5318
There is a workaround where you alter the command-line for each worker process, although the API was not meant to be used this way (the workaround might stop working in the future). Here is the source code from the github issue:
var cluster = require('cluster');
var http = require('http');
if (cluster.isMaster) {
var debug = process.execArgv.indexOf('--debug') !== -1;
cluster.setupMaster({
execArgv: process.execArgv.filter(function(s) { return s !== '--debug' })
});
for (var i = 0; i < 2; ++i) {
if (debug) cluster.settings.execArgv.push('--debug=' + (5859 + i));
cluster.fork();
if (debug) cluster.settings.execArgv.pop();
}
}
else {
var server = http.createServer(function(req, res) {
res.end('OK');
});
server.listen(8000);
}
Quick simple fix ( where using chrome://inspect/#devices )
var child = require('child_process');
child.fork(__dirname + '/task.js',[],{execArgv:['--inspect-brk']});
Then run your app without any --inspect-brk and the main process won't debug but the forked process will and no conflicts.
To stop a fork conflicting when debugging the main process ;
child.fork(__dirname + '/task.js',[],{execArgv:['--inspect=xxxx']});
where xxxx is some port not being used for debugging the main process. Though I haven't managed to easily connect to both at the same time in the debugger even though it reports as listening.
I find that setting the 'execArgv' attribute in the fork func will work:
const child = fork('start.js', [], {
cwd: startPath,
silent: true,
execArgv: ['--inspect=10245'] });
if "process.execArgv" doenst work you have to try:
if (debug) {
process.argv.push('--debug=' + (40894));
}
this worked for me..
There are one more modern way to debug child (or any) process with Chrome DevTools.
Start your app with arg
--inspect
like below:
node --debug=9200 --inspect app/main.js
You will see the message with URL for each child process:
Debugger listening on port 9200.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9200/207f2ab6-5700-4fc5-b6d3-c49a4b34a311
Debugger listening on port 9201.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9201/97be3351-2ea1-4541-b744-e720188bacfa
Debugger listening on port 9202.
Warning: This is an experimental feature and could change at any time.
To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9202/8eb8384a-7167-40e9-911a-5a8b902bb8c9
If you want to debug the remote processes, just change the address 127.0.0.1 to your own.

Resources