Valgrind memory debugging for nodejs using child process - node.js

I am trying to debug a nodejs script which has dependencies on native bindings. That script also involves forking a child process. I am using valgrind to debug the memory issues with following options:
valgrind --leak-check=summary --show-leak-kinds=all --trace-children=yes --verbose node app.js
It only works if I set --trace-children=no, otherwise always failed.
I created following sample script to test the scenario and it seems valgrind does not work debugging child process running in node.
// main.js
var cp = require('child_process');
var child = cp.fork('./worker');
child.on('message', function(m) {
// Receive results from child process
console.log('received: ' + m);
});
// Send child process some work
child.send('Please up-case this string');
and
worker.js
process.on('message', function(m) {
// Do work (in this case just up-case the string
m = m.toUpperCase();
// Pass results back to parent process
process.send(m.toUpperCase(m));
});
And valgrind always failed with following error:
==10401== execve(0x1048a3150(/bin/bash), 0x1048a3638, 0x1048a3658) failed, errno 2
==10401== EXEC FAILED: I can't recover from execve() failing, so I'm dying.
==10401== Add more stringent tests in PRE(sys_execve), or work out how to recover.

Related

Descendent of a child process not receiving SIGTERM on ubuntu but receives on mac

So I have some code which runs a command in a spawned child process. I do this using the execa module.
const childProcess = execa.command('yarn start');
const localhostStarted = await waitForLocalhost({ port: 8000 });
expect(localhostStarted.done).toBe(true);
childProcess.kill('SIGINT', { forceKillAfterTimeout: 2000 });
The yarn start command executes webpack-dev-server in another child process of its own. However when I kill the childProcess that I spawned, it does not automatically kill its spawned webpack-dev-server process. It is known to be an issue here https://github.com/webpack/webpack-dev-server/issues/2168.
To fix this I add manual listeners for SIGINT & SIGTERM inside my script which runs when yarn start is called
['SIGINT', 'SIGTERM'].forEach((signal) => {
console.log('registering events');
process.on(signal, () => {
console.log('received signal', signal);
devServer.close(() => {
console.log('exiting proces');
process.exit(0);
});
});
});
This fixes the issue on my local machine and when I kill child process I spawn, it kills all its descendents i.e the dev-server process too.
However, this fix still does not work on CI, and since the child process gets killed on CI but not the dev-server process, my tests dont exit and keeps hanging.
My local machine is OSX 10.15 but on CI we use ubuntu. If I change CI to use macos 10.15, then the fix works on CI too.
I am unable to find any docs on this issue which explains the different behaviour on why the signal of SIGTERM is not received by the dev-server process on ubuntu machines but receives fine on mac machines.

How to REALLY kill a child_process nodejs

I'm using mocha with Nodejs to test my restApi.
When I run mocha, I tell my test to create a child_process and run the API so I can make requests to it.
The problem is whenever the test exits (finishing or crashing), it seems that the API keeps running on background. I've seen some answers here that instructs to manually kill the child process whenever the main process exits. So I did it like this:
export function startProcess(done) {
const child = spawn('babel-node', ["app.js"]);
child.stdout.on("data", function(data) {
data = data.toString();
// console.log(data.toString());
if(data.indexOf("Server online") > -1) done();
});
child.stderr.on('data', function(err) {
console.log("ERROR: ", err.toString());
});
child.on('exit', function(code) {
console.log("PROPERLY EXITING");
console.log("Child process exited with code", code);
});
process.on('exit', function(code) {
console.log("Killing child process");
child.kill();
console.log("Main process exited with code", code);
});
}
When the main process exits it does log "Killing child process", meaning that child.kill() was indeed called. But if I try to run my test again, when the spawn command gets called, the API throws an error
Error: listen EADDRINUSE :::3300
, meaning that the API is still running and that port address is taken.
So I have to run sudo pkill node to really kill all node process and then npm test works again.
Am I missing something? Is this really the way to achieve what I'm expecting?
I thought about using child_process.exec to run sudo pkill node on my process.on('exit') listener, but that doesnt seem like a smart thing to do.
This is happening both in Mac and Ubuntu.
Any suggestions?
Thanks
"exit" is an event that gets triggered when node finishes it's event loop internally, it's not triggered when you terminate the process externally.
What you're looking for is executing something on a SIGINT.
Have a look at http://nodejs.org/api/process.html#process_signal_events

Format output of spawned gulp process like the parent process

Usecase: On large projects it can be nice to separate small projects into folders of their own with their own build process.
The following setup basically works on both windows and mac - I get the output of the child gulp process logged in the console - only problem is that it's not colored like the output of the parent process.
var spawnCmd = require('spawn-cmd');
gulp.task('default', function () {
// Run all the parent projects tasks first
// ....
// ....
// ....
// When done, cd to child directory
process.chdir('./some-dir-that-has-a-gulpfile');
// Run `gulp` in the child directory
var child = spawnCmd.spawn('gulp', ['default']);
// And pipe the output to the current process
child.stdout.pipe(process.stdout);
});
My question is how to display the output of the child gulp process in exactly the same way as the normal gulp process.
Edit: Duplicate of Is it possible for child processes in Node.js to preserve colored output?
You should inherit the stdio of the parent process. This correctly pipes the output to the same output, with colors and all.
Because you are using gulp, you should also add the --color always flag, in order for gulp to properly detect that you want colors.
var spawnCmd = require('spawn-cmd');
gulp.task('default', function () {
// When done, cd to child directory
process.chdir('./some-dir-that-has-a-gulpfile');
// Run `gulp` in the child directory
var child = spawnCmd.spawn('gulp', ['default', '--color', 'always'], {stdio: 'inherit'});
});

Unable to spawn a custom .exe from express.js on Windows

I am using node.js/express.js on windows and I have a command I execute when a user takes a image and uploads up from there phone. Once it is uploaded I run myApp.exe to perform some openCV image processing and I output the updated images to a output directory that is a argument in the command below.
I am able to kick this off from my webapp using child_process.exec, but the performance is 60x slower if I run it at command line by itself. To increase the performance I was hoping to use Spawn, but I don't know if this is an accurate assumption, please let me know if it is not.
var exec = require('child_process').exec;
var child = exec('C:\\opt\\package_v030_package\\myApp.exe
--user="C:\\opt\\package_v030_package\\Phone\\'+file.filename+'"
--mv="C:\\opt\\package_v030_package\\mv\\'+req.body.detectionString+'.bmp"
--outPath="C:\\opt\\package_v030_package\\output"
--outputScaled
--outputScaledOverlaid');
child.stdout.on('data', function(data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function(data) {
console.log('stdout: ' + data);
});
child.on('close', function(code) {
console.log('closing code: ' + code);
//res.json("success")
});
I have tried to kick it off using spawn, but it fails to execute with the following: "error child process exited with code 4294967295". The code is below:
var spawn = require('child_process').spawn;
var cmd = spawn('cmd', ['/s',
'/c',
'C:\\opt\\package_v030_package\\myApp.exe',
'--user="C:\\opt\\package_v030_package\\Phone\\'+file.filename+'"',
'--mv="C:\\opt\\package_v030_package\\mv\\'+req.body.detectionString+'.bmp"',
'--outPath="C:\\opt\\package_v030_package\\output"',
'--outputScaled',
'--outputScaledOverlaid'
]);
cmd.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
cmd.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
cmd.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
It seems I am able to execute just myApp.exe from spawn because when I add any of my arguments it fails. Even when I hard code the variables that I inject. Is there an issue with my arguments or am I spawning myApp.exe incorrectly?
Update 1
I placed the command in a .bat and was able to execute it from node.js using spawn. It does not increase performance which leads me to believe that the decrease in performance is a limitation of node.js on the windows platform.
In addition, I performed a few tests using postman to see if I could optimize the call without anything else happening, but I did not succeed. I will leave this question open in the event this changes and node.js is able to better handle performance of a CPU intensive child process.
Update 2 & Answer
I was able to fix this by placing the command that we run at the command line into a java class taking in the detectionString as a parameter. Then from node I use spawn to kick off the .jar file. This caused the speed to increase significantly and run as if I was running it myself at command line.
I was able to fix this by placing the command that we run at the command line into a java class taking in the detectionString as a parameter. Then from node I use spawn to kick off the .jar file. This caused the speed to increase significantly and run as if I was running it myself at command line.

Running Node app through Grunt

I am trying to run my Node application as a Grunt task. I need to spawn this as a child process, however, to allow me to run the watch task in parallel.
This works:
grunt.registerTask('start', function () {
grunt.util.spawn(
{ cmd: 'node'
, args: ['app.js']
})
grunt.task.run('watch:app')
})
However, when changes are detected by the watch task, this will trigger the start task again. Before I spawn another child process of my Node app, I need to kill the previous one.
I can't figure out how to kill the process, however. Something like this does not work:
var child
grunt.registerTask('start', function () {
if (child) child.kill()
child = grunt.util.spawn(
{ cmd: 'node'
, args: ['app.js']
})
grunt.task.run('watch:app')
})
It appears that:
Even though I store the spawned process in a variable outside of the function context, it does not persist, so the next time the start task is run, child is undefined.
child has no kill function…
Take a look at grunt-nodemon which handles a lot of the headaches related to spawning a child process.
This is because grunt-contrib-watch currently spawns all task runs as child processes. So the variable child is not within the same process context. Fairly soon, grunt-contrib-watch#0.3.0 will be released with a nospawn option. This will let you configure the watch to spawn task runs within the same context and would make your above example work.
Take a look at this issue for a little more information:
https://github.com/gruntjs/grunt-contrib-watch/issues/45

Resources