Node.js Detached child process is invoked as interactive foreground process - javascript

I am invoking a detached child_process (in windows) like this
var stdout = fs.openSync('./out.log', 'a');
var stderr = fs.openSync('./out.log', 'a');
var child = child_process.spawn('node', ['./main.js'], {
detached: true,
stdio: [ 'ignore', stdout, stderr ],
env: process.env
});
child.unref();
The spawned process, i.e. main.js in turn forks some workers using child_process.fork.
Normally the child and sub-children processes should run in background, correct me if I am wrong. But in when I try, the sub-children processes are running as interactively in foreground. I don't know what is causing them to behave like this. Could anyone point what could be the problem?
If I set detached to false, it works fine, but then the original parent can't exit without having all children exited.

I think this may be a problem with node on windows.
I tried both your code and the sample code on the node documentation you are for sure referencing yourself at http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options on my Ubuntu virtual machine and it works just fine. Process is detached and keeps running and there is no output anywhere but to out.log because it is running successfully in the background.
I ran both a simple ping command and also ran a node instance on a javascript file like you are trying to do and both worked just fine.
I would recommend you do the same with a ping command in windows. . .
var child = child_process.spawn('ping', ['-n','25','localhost'],. . .
If that works like you would expect, there may be something inside your main.js that is causing the issue. If it doesn't work either, I would say you are up against a bug in node on windows and should report it.
Hope that helps some!

Related

Node spawn child process doesn't execute the command after exec child process in aws node 10 lambda

I am attempting to run 2 child processes, but one seems to be blocked and eventually times out the node lambda.
Environment:
AWS node 10 lambda running in a docker container.
Accesses ffmpeg and ffprobe via a lambda layer in the /opt/bin directory.
child_process.exec
I am running ffprobe in a child_process.exec to get the file format of an audio file. I am using exec because the output is a small json response (which shouldn't consume much memory).
child_process.spawn
Shortly after I run ffmpeg to convert the audio file to mp3 using child_process.spawn.
The problem is the FFMPEG child_process.spawn command doesn't run after ffprobe (even though ffprobe successfully completes). If I don't run the ffprobe command the FFMPEG command runs perfectly.
Which leads me to believing this is an issue with how I am dealing with child processes in node.
Is it possible the child_process.exec ffprobe command is somehow still running/ blocking the new ffmpeg (child_process.spawn) command from running - if so how do I check this?
When I access the running processes in the docker container only the new ffmpeg command seems to be running, although it consumes no memory and just hangs - seemingly doing nothing. I even tried launching the ffmpeg command from the docker cli (avoiding using the node env) and this works fine and runs as expected.
So it seems my issue wasn't really between exec and spawn, I am not 100% sure but I think it could be that the child process was preserved in the container and resumed in the next invocation of the lambda.
Changing to child_process.spawnSync waits until the child process exits and keeps things cleaner and I haven't encountered this problem since using this.
A more thorough explanation from someone else would be really appreciated.

How to fork a child process with electron

I have a simple nodeJS app that has a function to scrape file metadata. Since scraping metadata can be intensive I made the app run this as a child process using fork.
const metaParser = child.fork( fe.join(__dirname, 'parse-metadata.js'), [jsonLoad]);
Everything worked great until I ported this to electron. When run in main.js the process is successfully created, but immediately exits. I added some logging to parse-metadata.js and found out that parse-metadata.js executed successfully and ran long enough to run the first few lines of code and then exited.
How do I get electron to fork parse-metadata.js and keep it alive until the end?
I'm using electron v1.4.15 and Node v6
When using the detached option to start a long-running process, the process will not stay running in the background unless it is provided with a stdio configuration that is not connected to the parent.
Also it seems related to the env.
Look at this: https://github.com/electron/electron/issues/6868

How to fork a process of another module

TL;DR : How does one fork a process that is located outside of the current running process?
I'm trying to use child_process of Nodejs in order to start another nodejs process on the parent's process exit.
I successfully executed the process with the exec but I need the child process be independent of the parent, so the parent can exit without waiting for the child, hence I tried using spawn with the detached: true, stdio: 'ignore' option and unref()ing the process:
setting options.detached to true makes it possible for the child process to continue running after the parent exits.
spawn('node MY_PATH', [], {detached: true, stdio: 'ignore'}).unref();
This yields the :
node MY_PATH ENOENT error. which unfortunately I've failed resolve.
After having troubles achieving this with spawn and reading the documentationagain i figured i should actually use fork:
The child_process.fork() method is a special case of child_process.spawn() used specifically to spawn new Node.js processes.
fork() doesnt take a command as its' first argument, but a modulePath which i can't seem to fit since the script I'm trying to run as a child process isnt in the directory of the current running process, but in a dependency of his.
Back to the starting TL;DR - how does one fork a process that is located outside of the current running process?
Any help would be much appreciated!
EDIT:
Providing a solution to the spawn ENOENT error could be very helpfull too!
Following code should allow you to do what you need.
var Path = require('path');
var Spawn = require('child_process').spawn;
var relative_filename = '../../node_modules/bla/bla/bla.js';
Spawn('node', [Path.resolve(__dirname, relative_filename)], {detached: true, stdio: 'ignore'}).unref();
process.exit(0);

Node.js why does a child process not start right away?

I'm trying to write a global node command line program that will take any (windows or unix) console command I give to it and execute it in a new console window. I also want the program to exit after it has spawned its process so the console I'm using isn't blocked by a node script that has a child process running.
This is a simple version of what I have so far:
myScript.js:
var exec = require('child_process').exec;
exec("start startScript.cmd"); // windows start command opens a new cmd window
process.exit(0);
startScript.cmd:
mkdir test
I have also tried this (But this doesn't work even without the process.exit):
myScript.js:
var spawn = require('child_process').spawn;
var child = spawn('start', ['startScript.cmd'], { detached: true, stdio: ['ignore', 'ignore', 'ignore']});
child.unref();
process.exit(0);
The problem is, calling process.exit() seems to prevent the child process from fully starting and so nothing happens unless I do some setTimeout shenanigans. However the behavior seems random. On a different computer it behaves like I want it to. Both computers have the same version of node (v0.10.33).
The directory test is never made unless I remove the process.exit line or use a setTimeout on it.
Any idea why this happens or how to get around it? Keep in mind I don't want to wait until the child process is finished. I want to be able to return to my command line immediately.
Thanks!
I figured it out.
The answer is: don't use exec and don't use start or call or any other weird windows command in the spawn call. Set the CWD if need be in the spawn options and either spawn what you want directly or make a OS specific script that calls your command if it still isn't working. One example of a windows script is literally just:
%*
That way, start or any other weird windows command will be executed correctly (but do you really need them?).

Automate UI testing with Javascript, node - starting & stopping a web server

I'm currently investiagating automated UI testing using JavaScript on windows with node.js and phantom.js and unsurprisingly I've found many frameworks that can help in this regard (casper.js, Buster.js, etc).
The one thing that seems to be missing from the frameworks I have looked at so far is stopping and starting a web server to server the web pages so that testing framework can perform its testing. One exception is WebDriver.js which uses the Selenium standalone server but this relies on a server written Java and at the moment I'd prefer to find a node based solution if at all possible.
From the node perscpective I've looked at Connect.js and also Http-Server (which I particularly like) but the issue is starting and stopping these from a JavaScript test.
I've attempted to create a casper.js test that would interact with a server, run the test and then stop the server but I can't get it to work, here's an example script
var childProcess = require('child_process').spawn('http-server', '/TestSite');
casper.test.begin("Load-page", 1, function suite(test){
casper.start('http://localhost:8080/',function(){
test.assertTitle("test page");
});
casper.run(function(){
test.done();
childProcess.kill();
});
});
I call this from the command line using the following command (casper is in my Path variable):
casperjs Load-page testFile.js
What I was hoping would happen is the http-server would start, casper would start the test and then after the test was run the http-server would be killed.
I've also tried similar with Connect:
var server= connect.createServer(connect.static('/TestSite')).listen(8080)
casper.test.begin("Load-page", 1, function suite(test){
casper.start('http://localhost:8080/',function(){
test.assertTitle("test page");
});
casper.run(function(){
test.done();
server.stop();
});
});
But again with no luck.
I can run the Casper sample tests which work and I've also got Node in my Path as well and can call the REPL from the command prompt.
The directory structure is:
Code
/TestSite
/node_modules
and I run the tests from the Code folder.
Am I simply unable to do this or am I just not getting how it should work?
When you say "no luck" what do you mean?
The connect example looks mostly OK, and I'd prefer it over spawning a subprocess. Bear in mind that listen is potentially async so the server might not be available immediately though. The second param to listen is a callback that will be run once the server is listening - maybe try running the tests in that callback instead?
Pro Tip: Don't rely on port 8080 always being free on whatever machine you're running on - passing in 0 for the port will cause the server to start on a random port, you can then do server.address().port in the listen callback to get the port that was chosen
I managed to get it working using a combination of differebt scripts and using child_process spawn.
I created a script called startServer.js that would start the server using Connect:
var connect = require('connect');
var server= connect.createServer(connect.static('TestSite'));
server.listen(8081);
I created another script runTests.js that would call the server script via spawn and then call Casper, again via spawn, and run all the capser tests that are in a folder called tests relative to where the script is run from.
var child_process = require('child_process');
var stillRunning = true;
var server = child_process.spawn('node', ['createServer.js']);
var casper = child_process.spawn('casperjs', ['test tests']);
casper.stdout.on('data', function(data){
console.log(data.toString());
});
casper.stderr.on('data', function(data){
console.log('Error: ' + data);
});
casper.on('exit', function(code){
server.kill();
process.exit(0);
});
To use this at the command prompt navigate to the folder where the script is and then run node runTests.js and the server will be started and the tests run against the site

Categories