Node Spawn process outliving the main node process - node.js

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

Related

node.js child_process spawn repl

Nodejs Child Process: write to stdin from an already initialised process
I saw this link, so I try like this :
const { spawn } = require('child_process');
const child = spawn('node');
child.stdin.setDefaultEncoding('utf-8');
child.stdout.pipe(process.stdout);
child.stdin.cork();
child.stdin.write("10+20\n");
child.stdin.uncork();
but this code does not output anything, so what should I do?

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 fork a child process that listens on a different debug port than the parent

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");

Nodejs Child Process: write to stdin from an already initialised process

I am trying to spawn an external process phantomjs using node's child_process and then send information to that process after it was initialized, is that possible?
I have the following code:
var spawn = require('child_process').spawn,
child = spawn('phantomjs');
child.stdin.setEncoding = 'utf-8';
child.stdout.pipe(process.stdout);
child.stdin.write("console.log('Hello from PhantomJS')");
But the only thing I got on the stdout is the initial prompt for phantomjs console.
phantomjs>
So it seems the child.stdin.write is not making any effect.
I am not sure I can send additional information to phantomjs ater the initial spawn.
You need to pass also \n symbol to get your command work:
var spawn = require('child_process').spawn,
child = spawn('phantomjs');
child.stdin.setEncoding('utf-8');
child.stdout.pipe(process.stdout);
child.stdin.write("console.log('Hello from PhantomJS')\n");
child.stdin.end(); /// this call seems necessary, at least with plain node.js executable
You need to surround your write by cork and uncork, the uncork method flushes all data buffered since cork was called. child.stdin.end() will flush data too, but no more data accepted.
var spawn = require('child_process').spawn,
child = spawn('phantomjs');
child.stdin.setEncoding('utf-8');
child.stdout.pipe(process.stdout);
child.stdin.cork();
child.stdin.write("console.log('Hello from PhantomJS')\n");
child.stdin.uncork();

Resources