Child process isn't logging when receiving SIGINT - node.js

I am trying to kill a previously forked child process in Node.js. I'm unsure if it's working because my console.log line is not being hit in the child process.
Here is what I'm calling from the parent:
console.log("sending SIGINT from main");
child.kill("SIGINT");
And in the child:
process.on("SIGINT", () => {
console.log("Killing bot");
DBS.Bot.destroy();
process.exit();
});
The only console log I see is from the parent.

When spawning a NodeJS child process, this child process' stdout is not the same as the parent process' stdout stream, which is why you do not see any logging output. You can add the following code to copy any output of your child process to your main process' stdout stream:
child.stdout.on ("data", (data) => {
console.log ("child process: " + data.toString ());
});
In some circumstances, it can be useful to also capture stderr output, which is the stream NodeJS' console.err () writes to:
child.stderr.on ("data", (data) => {
console.log ("child process error: " + data.toString ());
});
Also, to make sure a child process has exited with a non-error code, i.e. the exit code is 0, you can use NodeJS' child_process "exit" signal:
child.on ("exit", (code, signal) => {
if (signal !== null) console.log ("child exited due to signal '" + signal + "'");
else console.log ("child exited with code " + code);
});
For more information, make sure to check out NodeJS' documenation on child_process.

Related

child process doesn't exit

Following is my gulp task:
httpServer.on("close", (code, signal) => {
console.log(
`child process terminated due to receipt of signal ${signal}, code ${code}`
);
console.log("httpServer close");
resolve();
})
);
await new Promise((resolve) => setTimeout(resolve, 2e3));
httpServer.kill("SIGINT");
await httpServerClose;
console.log("here");
I got following output:
Available on:
http://127.0.0.1:5001
http://192.168.31.122:5001
http://172.21.96.1:5001
http://172.18.192.1:5001
Hit CTRL-C to stop the server
child process terminated due to receipt of signal SIGINT, code null
httpServer close
here
[13:32:57] Finished 'build:release' after 2.01 s
The problem is port 5001 is still in use.
I'm on windows 10, node v16.13.1
.kill() doesn't guarantees that the process will successfully terminate. You may check for the resulting boolean that kill() returns, but that only indicates wheter the signal was delivered or not.
childProcess.on('close', (code, signal) => {
console.log(
`child process terminated due to receipt of signal ${signal}`);
});
// Send SIGHUP to process.
const signalDelivered = childProcess.kill('SIGHUP');
console.log(signalDelivered)
For some reason, the childProcess is still running / crashed or the SIGINT was not handled correctly.
My suggestion is that you implement "Graceful shutdown".
Remember, if in your childProcess code you are handling process.on('SIGINT', ..),you need to close the server that is listening connections and then call process.exit(0).
const server = app.listen(5001)
process.on('SIGINT',function(){
server.close(err => {
//exit after server is not listening anymore
process.exit(err ? 1 : 0)
})
});

NodeJS bug in Linux when executing child_process.fork?

I cannot reliably get a forked child process to send back a message to the parent that exceeds 219262 bytes.
The issue is only on Linux. In Windows, it works as expected. And this issue seems have been introduced between Node versions 1.0.1 and 1.0.2 - works fine on Node versions prior to 1.0.1 but not after.
(the maxBuffer option is not relevent for child_process.fork, it only applies to child_process.exec and child_process.execFile)
Below is the failing sample. Executing "node parent" on the command line will fail to output the child's "messageToParent" if it exceeds 219262 bytes on Linux.
parent.js is:
var cp = require('child_process');
var child = cp.fork('./child', [], {});
console.log('>>>PARENT ---> SENDING MESSAGE TO CHILD');
child.send({});
child.on('message', function(msg) {
console.log('>>>PARENT ---> MESSAGE RECEIVED FROM CHILD = ' + JSON.stringify(msg));
});
child.on('error', function(err) {
console.log('>>>PARENT ---> ERROR FROM CHILD. err = '+ err);
});
child.on('exit', function(code, signal) {
console.log('>>>PARENT ---> EXIT FROM CHILD. code='+code+' signal = '+ signal);
});
child.on('close', function(code, signal) {
console.log('>>>PARENT ---> CLOSE FROM CHILD. code='+code+' signal = '+signal);
});
child.on('disconnect', function() {
console.log('>>>PARENT ---> DISCONNECT FROM CHILD');
});
child.js is
process.on('message', function(messageFromParent) {
console.log('>>>>>>CHILD ---> RECEIVED MESSAGE FROM PARENT');
var messageToParent = "It would be too long to post on stackoverflow, but if I make this string longer than 219262 bytes, it fails to return to the parent in Linux. There is no such issue in Windows";
var ret = process.send(messageToParent);
console.log('>>>>>>CHILD ---> SENDING MESSAGE TO PARENT process.send returned ' + ret);
process.exit(0);
});
process.on('uncaughtException', function(err) {
process.send({ output: {ERROR:err} });
process.exit(-1);
});
Posting an answer in case anyone else stumbles into this issue (https://github.com/nodejs/node/issues/36268)
The above child.js works perfectly in Node versions prior to 1.0.1 since child_process.fork() used to be synchronous. So "process.send(messageToParent)", followed by "process.exit(0)" will always return messageToParent to parent.js.
In later versions of Node, however, process.send() is async. Therefore, the child must exit via process.exit() within a process.send callback, else a race condition is created between V8 javascript thread and IPC pipe.
Also - in Windows, the default IPC pipe buffer is large enough that the message is always returned to parent prior to child exiting. This is not the case in Linux. This explains why the above code works in Windows even with later versions of Node where process.send() is async.

Start and Stop Python Script from NodeJS?

How can I start and stop a python script from a NodeJS server? I have seen the module "python-shell", but it doesn't provide a way to kill the script after running it.
Use child_process.
Example from the doc:
const { spawn } = require('child_process');
const child = spawn('python3', ['script.py']);
child.on('close', (code, signal) => {
console.log(
`child process terminated due to receipt of signal ${signal}`);
});
// Send SIGTERM to process
child.kill('SIGTERM');

Node.js child process exits with SIGTERM

I'm spawning a child process using Node 6.9.
const child = require('child_process').execFile('command', args);
child.stdout.on('data', (data) => {
console.log('child:', data);
});
child.stderr.on('data', (data) => {
console.log('child:', data);
});
child.on('close', (code, signal) => {
console.log(`ERROR: child terminated. Exit code: ${code}, signal: ${signal}`);
});
My child process runs for ~1m 30s but then I get this output from my Node.js program:
ERROR: child terminated. Exit code: null, signal: SIGTERM
What terminates my child process and why?
Edit:
I've added killSignal: 'SIGILL' as an option.
var child = require('child_process').execFile('geth', args, { killSignal: 'SIGILL'});
Now, I get this:
ERROR: go-ethereum terminated. Exit code: 2, signal: null
I found the problem and a solution.
From https://nodejs.org/dist/latest-v6.x/docs/api/child_process.html#child_process_child_process_execfile_file_args_options_callback
maxBuffer largest amount of data (in bytes) allowed on stdout or stderr - if exceeded child process is killed (Default: 200*1024)
I can set the maxBuffer option higher.
childProcess.execFile('geth', args, { maxBuffer: 400 * 1024});
It seems you can't disable the maxBuffer option, not even by setting it to 0. But it seems to be on purpose.

Prevent sending data to stdin if spawn fails

In my Node.js (v0.10.9) code I'm trying to detect 2 cases:
an external tool (dot) is installed - in that case I want to send some data to stdin of created process
the external tool is not installed - in that case I want to display warning and I don't want to send anything to process' stdin
My problem is that I don't know how to send data to child's stdin if and only if the process was spawned successfully (i.e. stdin is ready for writing).
Following code works fine if dot is installed, but otherwise it tries to send data to the child although the child wasn't spawned.
var childProcess = require('child_process');
var child = childProcess.spawn('dot');
child.on('error', function (err) {
console.error('Failed to start child process: ' + err.message);
});
child.stdin.on('error', function(err) {
console.error('Working with child.stdin failed: ' + err.message);
});
// I want to execute following lines only if child process was spawned correctly
child.stdin.write('data');
child.stdin.end();
I'd need something like this
child.on('successful_spawn', function () {
child.stdin.write('data');
child.stdin.end();
});
From the node.js docs: http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options
Example of checking for failed exec:
var spawn = require('child_process').spawn,
child = spawn('bad_command');
child.stderr.setEncoding('utf8');
child.stderr.on('data', function (data) {
if (/^execvp\(\)/.test(data)) {
console.log('Failed to start child process.');
}
});
Have a look at core-worker:
https://www.npmjs.com/package/core-worker
This package makes it a lot easier to handle processes.
I think what you want to do is something like that (from the docs):
import { process } from "core-worker";
const simpleChat = process("node chat.js", "Chat ready");
setTimeout(() => simpleChat.kill(), 360000); // wait an hour and close the chat
simpleChat.ready(500)
.then(console.log.bind(console, "You are now able to send messages."))
.then(::simpleChat.death)
.then(console.log.bind(console, "Chat closed"))
.catch(() => /* handle err */);
So if the process is not started correctly, none of the .then statements are executed which is exactly what you want to do, right?

Resources