node.js: How to spawn detached child in foreground and exit - node.js

According to the docs for child_process.spawn I would expect to be able to run a child process in the foreground and allow the node process itself to exit like so:
handoff-exec.js:
'use strict';
var spawn = require('child_process').spawn;
// this console.log before the spawn seems to cause
// the child to exit immediately, but putting it
// afterwards seems to not affect it.
//console.log('hello');
var child = spawn(
'ping'
, [ '-c', '3', 'google.com' ]
, { detached: true, stdio: 'inherit' }
);
child.unref();
Instead of seeing the output of the ping command, it simply exits without any message or error.
node handoff-exec.js
hello
echo $?
0
So... is it possible in node.js (or at all) to run a child in the foreground as the parent exits?
Buggy Node Versions
I found that removing console.log('hello'); allows the child to run, however, it still doesn't pass foreground stdin control to the child. That's obviously not intended, therefore something must be buggy in the version of node I was using at the time...
https://github.com/nodejs/node/issues/5549

Solution
The code in the question was actually correct. There was a legitimate bug in node at the time.
'use strict';
var spawn = require('child_process').spawn;
console.log("Node says hello. Let's see what ping has to say...");
var child = spawn(
'ping'
, [ '-c', '3', 'google.com' ]
, { detached: true, stdio: 'inherit' }
);
child.unref();
The snippet above will run effectively the same as if it had been backgrounded by the shell:
ping -c 3 google.com &

You are missing
// Listen for any response:
child.stdout.on('data', function (data) {
console.log(data.toString());
});
// Listen for any errors:
child.stderr.on('data', function (data) {
console.log(data.toString());
});
and you don't need the child.unref();

Related

nodejs: do not wait spawned process

I am using child_process.spawn for running some app and I want to execute some actions after this app was started. But spawn blocks main process
const spawnAsync = Promise.promisify(require('child_process').spawn);
console.log('BEFORE');
await spawnAsync('../node_modules/.bin/some-app', ['-p', '3333'], {
detached: true
});
console.log('AFTER');
In my console, I see BEFORE and AFTER would be logged only after killing process on 3333 port. I don't want to wait spawned process, I want to do some actions after spawnSync calling.
Looking at spawn documentation you should use it that way
const childProcess = require('child_process');
const newProcessDescriptor = childProcess.spawn(
'../node_modules/.bin/some-app',
['-p', '3333'],
{ detached: true }
);
newProcessDescriptor.on('error', (error) => {
console.log(`child process creating error with error ${error}`);
});
newProcessDescriptor.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});

NodeJs script with child_process spawn on Windows, why I need 'shell: true' for ENOENT error?

I'm using this code:
const {
spawn
} = require('child_process');
let info = spawn('npm', ["-v"]);
info.on('close', () => {
console.log('closed');
}
But I have this error:
events.js:182
throw er; // Unhandled 'error' event
^
Error: spawn npm ENOENT
at exports._errnoException (util.js:1022:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:189:19)
at onErrorNT (internal/child_process.js:366:16)
at _combinedTickCallback (internal/process/next_tick.js:102:11)
at process._tickCallback (internal/process/next_tick.js:161:9)
at Function.Module.runMain (module.js:607:11)
at startup (bootstrap_node.js:158:16)
at bootstrap_node.js:575:3
If I use instead:
let info = spawn('npm', ["-v"], {shell: true});
it works!
But why I need shell: true? I need also to see the stdout of that spawn, so I'm also using this:
let info = spawn('npm', ["-v"], {shell: true, stdio: 'inherit'});
It's correct?
While calling spawn itself, there is no npm command under spawn. Thus you got that error message. Instead of using spawn itself, while adding shell: true, spawn will use shell of your system to run that command. Since your system has npm, it works.
let info = spawn('npm', ["-v"], {shell: true, stdio: 'inherit'}); It's correct?
The code is fine if your parameters of spawn are controllable. But generally, I suggest use pure spawn without using shell. The risk will reduce without touching shell directly.
Since you need the stream return from spawn. I have checked other solution here. Without shell: true, You can use the code:
const {
spawn
} = require('child_process');
let projectPath = ''//the path of your project
let info = spawn('npm', ['-v'], { cwd: projectPath });
let result = '';
info.stdout.on('data', function(data) {
result += data.toString();
console.log(result);
}

How to restart nodejs server in order to apply changes, when nodejs app is hosted through Apache

I use apache server to redirect to the NodeJS server on request of a specific domain. But when I add some functions to js code(server code), it says something like "not defined", even I tried to restart apache server, and killed all the node related processes.
What should I do now?
Run your node server with forever. There are other monitoring libraries out there as well.
The idea is that when files change (which can be white-listed), the app will be restarted. You need this if passing traffic through Apache, as restarting Apache will not restart the Node app, which needs to restart to read in your changes.
I use a script like this to start my app with forever, and I use it during development with node start.js or in production with some environment variables to config my Node env, and an "on boot" service so it runs on machine start (I use upstart).
/*jslint node: true */
"use strict";
/**
* File to start using forever, logs crashes, restarts on file changes, etc.
*/
var cmd = ( process.env.DBG ? "node --debug" : "node" );
var forever = require( 'forever' ),
//exec = require('child_process').exec,
child = new( forever.Monitor )( 'node', {
'silent': false,
'pidFile': 'pids/forever-app.pid',
'watch': true,
'command': cmd,
'args': ['app.js' ],
//"max" : 10,
'watchDirectory': './', // Top-level directory to watch from.
'watchIgnoreDotFiles': true, // whether to ignore dot files
'watchIgnorePatterns': [ 'log/*', 'node_modules/*', 'pids/*',
'dbscripts/*', 'test/*',
'curlcookies',
'.svn/*', ], // array of glob patterns to ignore, merged with contents of watchDirectory + '/.foreverignore' file
'logFile': 'log/forever.log', // Path to log output from forever process (when daemonized)
//'outFile': 'logs/ijoin-forever.out', // Path to log output from child stdout
'errFile': 'log/forever.err'
} );
child.on( "exit", function() {
console.log( 'app.js has exited!' );
} );
child.on( "restart", function() {
console.log( 'app.js has restarted.' );
} );
child.on( 'watch:restart', function( info ) {
console.error( 'Restaring script because ' + info.file + ' changed' );
} );
child.start();
forever.startServer( child );
process.on( 'SIGINT', function() {
console.log( "\nGracefully shutting down \'node forever\' from SIGINT (Ctrl-C)" );
// some other closing procedures go here
process.exit();
} );
process.on( 'exit', function() {
console.log( 'About to exit \'node forever\' process.' );
} );
process.on( 'uncaughtException', function( err ) {
console.log( 'Caught exception in \'node forever\': ' + err );
} );

Launching Two Node Child Processes From Single Gulp File Results In Error: listen EADDRINUSE

I'd like to manage two apps with one gulpfile. I can launch them both with the following code. However, when I modify one of the files, and gulp.watch restarts the server, I get Error: listen EADDRINUSE. Something must be wrong in my gulp server task, but what is it?
// Dependencies
var gulp = require('gulp'),
spawn = require('child_process').spawn,
node;
// Server Task
gulp.task('server', function() {
if (api) node.kill();
if (dashboard) node.kill();
var api = spawn('node', ['./api/server.js'], {
stdio: 'inherit'
});
var dashboard = spawn('node', ['./dashboard/server.js'], {
stdio: 'inherit'
});
api.on('close', function(code) {
if (code === 8) console.log('API – Error detected, waiting for changes...');
});
dashboard.on('close', function(code) {
if (code === 8) console.log('Dashboard – Error detected, waiting for changes...');
});
});
// Watch Statement
gulp.task('default', ['server'], function() {
// Watch files for changes
gulp.watch(alljsLocations, ['server'], function() {});
});

Why is my Node child process that I created via spawn() hanging?

I am using spawn() to make a git call. Sometimes it works fine but others it appears to be hanging. I see no events firing (error, exit, close) yet I see evidence that the process did in fact complete successfully.
var spawn = require('child_process').spawn;
spawn('git', ['push', 'origin', 'master'])
.on('error', function(error) {
console.log("ERROR: DETAILS: " + error);
})
.on('close', function(code) {
console.log("SUCCESS: CODE: " + code);
})
.on('exit', function(code) {
console.log("EXIT: CODE: " + code);
})
As it turns out once the stderr buffer exceeds 24kb you must be reading from it or you not see any events for completion. Possible workarounds:
Set the stdio option on the spawn call.
spawn('git', ['push', 'origin', 'master'], {stdio: 'ignore'});
See Node ChildProcess doc for all of the possibilities - there are lots.
Add an on(data) handler.
var git = spawn('git', ['push', 'origin', 'master']);
...
git.stderr.on('data', function(data) {
// do something with it
});
Pipe it to stdout / stderr. This may be too verbose for your application but including it for completeness.
var git = spawn('git', ['push', 'origin', 'master']);
...
git.stderr.pipe(process.stderr);
git.stdout.pipe(process.stdout);

Resources