Start and Stop Python Script from NodeJS? - node.js

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

Related

Why in node, child_process `spawn` has no killSignal option but `spawnSync` has?

Additionally, how to spawn a child process that ignore SIGTERM and can only be killed by SIGKILL?
Because this option is associated with the timeout option.
In spawn you have to decide when you kill the process.
Example: (from doc)
const { spawn } = require('child_process');
const grep = spawn('grep', ['ssh']);
grep.on('close', (code, signal) => {
console.log(
`child process terminated due to receipt of signal ${signal}`);
});
// Send SIGHUP to process
grep.kill('SIGHUP');

How to catch child_process restarting/forking itself

I am trying to get a node script to run another command with child_process, which starts up a server, but this server has 'live reload' functionality.
As far as I understand, as soon as anything changes, the child process restarts, and my parent process continues as if the child died/exited.
I want my parent process to re-connect to a newly forked/spawned child.
Is there any way to do this?
const command = 'server --listen 7070';
const process = child_process.exec(command);
process.stdout.on('data', (data) => {
console.log(data);
});
process.on('exit', (event) => {
console.log('The child process exited')
});
In this example, the server keeps running, but the stdout processing stops after the child process restarts itself for the first time.

Killing a process that spawned a process

I'm having trouble stopping a node.js process that spawns a child process. If I run the .js process from Terminal, I can stop it using Ctrl+C. But if I spawn it from a NodeJS app, I cannot kill it using kill("SIGINT") -- it just keeps going and continues to report stdout.
Here's the setup. I have a script, lets call it docker.js and it does this:
// docker.js
child_process.spawn("docker-compose", ["up", "-d", ...args], { stdio: 'inherit' });
The docker-compose up command does a lot of things and runs for awhile, sometimes for several minutes.
If I run ./docker.js from Terminal, I can consistently break out at any point by pressing Ctrl+C.
If I spawn docker.js from inside a different NodeJS app (in my case an Electron app), using spawn() or fork():
// DockerApp.js
const dir = `path/to/dockerjs/file/`;
// Tried this with and without `detached: true`
const child = spawn("node", [`./docker.js`, ...args], { cwd: dir, env, detached: true });
// Also tried this, which uses Electron's packaged node process
const child = fork(`./docker.js`, args, { cwd: dir, env, silent: true });
And I listen for stdout and stderr and close:
child.stdout.on("data", data => {
console.log(`stdout: ${data}`);
});
child.stderr.on("data", data => {
console.log(`stderr: ${data}`);
});
child.on("close", code => {
console.log(`child process exited with code ${code}`);
});
Everything works fine (I see expected output and eventually "close" after completion), but if I try to stop the process before completion like this:
child.kill("SIGINT"); // Equivalent to Ctrl+C in terminal
The child process just keeps running, and I keep getting docker-compose output through stdout.
I've tried for awhile but I cannot figure out how to stop docker.js when spawned as a child process from NodeJS/Electron app. I thought Ctrl+C from Terminal and child.kill("SIGINT") would have the same behavior, but it doesn't.
Can anyone explain what is going on here? And how can I reliably kill this docker.js child process from my NodeJS app?
Try something like this in child process:
process.on('SIGINT', () => {
console.log('Received SIGINT');
process.exit(0);
});

Sending message from child process to parent process when creating child_process with exec()

I have a parent process in Node.JS which creates a child process through calling exec.
I want to wait until the child process finish and return the status of the child process.
I don't want to use spawn or fork.
I'm creating the child_process with require('child_process').exec
I need the child process to send message to the parent process through IPC:
function foo()
{
const exec = require('child_process').exec;
const cmd = `cd /usr/lib/bin' && db-migrate --config "config/${environmentName}.json" -e ${environmentName} -v true up --force-exit`;
const child = exec(cmd, (error, stdout, stderr) => {
//...
});
child.on('exit', (code) => {
//from here i want to know if there was a problem in child process
//can I use IPC to send messages?
});
//wants to return the child status code from here
return child_status_code;
}
How can i solve this problem?
How can I use IPC from child process to parent process?
If there is a IPC channel created in process, you are able to send message from child to parent by "process.send“. It is addressed in documentation of Nodejs.
The IPC channel is only available by "fork". "fork" has the first parameter is module path.

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