How to kill node.exe child process? - node.js

I have the following piece of code with the "npm start" argument starting a node server instance :
const childProcess = require("child_process");
// running server before tests
before(function(done) {
childProcess.exec(["npm start"], function(err, out, code) {
if (err instanceof Error)
throw err;
process.stderr.write(err);
process.stdout.write(out);
process.exit();
});
setTimeout(done, 5000);
});
//run tests
require("./customer-individual.js");
require("./customer-organization.js");
After tests run the node server instance is still running somewhere as a background process . How can i kill it ?

You can use the following:
const child = childProcess.exec(["npm start"], function(err, out, code) {
// ...
});
child.kill(); // same as child.kill('SIGTERM');
console.log(child.killed); // will log true
Or any other signal, please refer to the docs: https://nodejs.org/api/child_process.html#child_process_child_kill_signal

Related

Killing a Shell

I'm not sure this is a bug or feature, but when killing a shell (using kill -9 <pid>) it doesn't exit the process, as in it calls the exit event but all code continues running. Here is my code
// index.js
const { spawn } = require("child_process");
const deploy = spawn(`node server`, {
shell: true,
});
console.log(deploy.pid); // I use this to get the PID so i can use the kill command
deploy.stdout.on("data", (data) => {
console.log(data.toString());
});
deploy.stderr.on("data", (data) => {
console.log(data.toString());
});
deploy.on("exit", (code) => {
console.log("exit");
});
// server.js
const app = require("express")();
app.use("/", (req, res) => {
console.log("debug");
res.send("Hello, World");
});
app.listen(8000, () => console.log("Site Online"));
According to the documents, using the sh command on Linux with the -c flag, 1) Fixes the problem of it not closing, 2) Allows you to run multiple commands without the shell option that causes the problem in the first place.
Example:
const deploy = spawn("sh", ["-c", `node server && ls`], {
stdio: ["inherit", "inherit", "inherit"],
});

Stop node server from another file

I have the following two files.
file1.js and file2.js
From file1.js, I start a node server that exists in files2.js by using Node exec from child process.
What I would like to do is, start the server that exists file2.js from file1.js by calling exec or spawn method from child_process. Stop it after 10s or so and restart the server again. How could I achieve this?
What I've tried is that, after I started the server, I called process.exit() and then tried to execute the exec function again, but since the process has exited, the second call to exec never actually reached.
I want to achieve this without using any external package though.
One way to do this is setTimeout():
const { exec } = require('child_process');
let stopped = false;
exec('command to start the server in file two', (err, stdout, stderr) => {
if (err) {
// handle error
} else {
// do stuff
}
});
setTimeout(function(){
exec('stop the server in file two', (err, stdout, stderr)=>{
stopped = true;
if(err){
// handle error
} else {
// do stuff
}
})
}, 10000);
if(stopped) {
exec('start server again', (err, stdout, stderr)=>{
stopped = false;
if(err){
// handle error
} else {
// do stuff
}
})
}

Contextify : How to catch async errors

I need to run unsafe JS script in node and be able to recover from errors.
The script can use async functions so I use contextify instead of node built in VM module.
The problem is that errors in async code in the script crash the node process.
Here is my test :
var contextify = require('contextify');
var context = {
console:{
log:function(msg){
console.log('Contextify : '+msg);
}
},
setTimeout:setTimeout
};
console.log("begin test");
contextify(context);
try{ // try to run unsafe script
//context.run("console.log('Sync user script error');nonExistingFunction();"); // works
context.run("setTimeout(function(){ console.log('Async user script error');nonExistingFunction(); },2000);"); // crash node process
}catch(err){
console.log("Recover sync user script error");
}
console.log("end test");
How can I catch async errors ?
I solved the problem by using child_process to create a thread for the script to execute in :
//main.js
var child_process = require('child_process');
var script = child_process.fork("scriptrunner.js");
script.on('error',function(err){
console.log("Thread module error " + JSON.stringify(err));
});
script.on('exit',function(code,signal){
if(code==null)
console.log("Script crashed");
else console.log("Script exited normally");
});
script.send("setTimeout(function(){ console.log('Async user script error');nonExistingFunction(); },2000);");
//scriptrunner.js
var contextify = require('contextify');
var context = {
console:{
log:function(msg){
console.log('Contextify : '+msg);
}
},
setTimeout:setTimeout
};
contextify(context);
process.on('message', function(js) {
try{
context.run(js);
}catch(err){
console.log("Catch sync user script error " + err);
}
});
So now if the script crashes it crash its own process and not the main node process. The downside is that I can't pass complex object (such as my context) between my main process and the script's thread, I need to find a workaround for that.

forever.list returns null in node.js code

Cannot use forever.list method in node.js code ...
var forever;
forever = require('forever');
forever.startServer();
forever.list("", function(result) {
return console.log(result);
});
... prints null in console.
Although in terminal when run forever list, I see running precesses.
❯ forever list
info: Forever processes running
data: uid command script forever pid logfile uptime
data: [0] 1QNd /usr/local/bin/node app.js 29937 29979 /Users/user/.forever/1QNd.log 0:0:26:23.55
And I want to get the same date inside node.js script.
Maybe I use list with invalid arguments. First argument format - I pass empty string, because don't know what to pass.
forever.list is a cli command, so you can not use directly in your code. If you are using forever programatically you should install forever-monitor.
So maybe you can call the cli command, e.g.:
var exec = require('child_process').exec;
function execute(command, callback) {
exec(command, function(err, stdout, stderr) {
callback(stdout);
})
};
execute('forever list', function(ret) {
console.log(ret);
});
out:
info: Forever processes running
data: uid command script forever pid logfile uptime
data: [0] OmsO /usr/bin/node /home/atupal/Dropbox/src/github/nodeblog/server.js 13171 13173 /home/atupal/.forever/OmsO.log 0:0:0:4.164
This answer in forever 0.15.2
Please see forever list command code in cli.js
https://github.com/foreverjs/forever/blob/master/lib/forever/cli.js#L428
//
// ### function list ()
// Lists all currently running forever processes.
//
app.cmd('list', cli.list = function () {
forever.list(true, function (err, processes) {
if (processes) {
forever.log.info('Forever processes running');
processes.split('\n').forEach(function (line) {
forever.log.data(line);
});
}
else {
forever.log.info('No forever processes running');
}
});
});
Expect your code.
var forever = require('forever');
// If set 'true' to #format, return 'processes' is formatted strings.
forever.list(true, function (err, processes) {
console.log(err);
console.log(processes);
});
// If set 'false' to #format, return 'processes' is object.
forever.list(false, function (err, processes) {
console.log(err);
console.dir(processes);
});

How do I cleanly shutdown mongodb from node.js?

I am running mongodb as a child process from node.js and require to shut down and restart on demand. using Child_Process.kill("SIGINT") would appear to be the correct way but but it leaves mongo in a confused state which won't restart until repaired (or the lockfile is deleted) Is there a better way to do this?
Thanks,
Andy
Doing kill("SIGINT") cause the database to shut down without going through the required steps and could lead to corrupt data files. So i would not recommend do this.
Normal way to stop database is send command { "shutdown" : 1 } or db.shutdownServer() from mongodb shell, but I don't know exactly how to do it from node.js driver.
you can try something like this:
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://localhost:27017/admin", function(err, db) {
if (err) {
console.log('mongodb is not running');
process.exit(0);
}
else {
db.command({
shutdown : 1
}, function(err, result) {
console.log('shutting down mongodb - ', err.message);
process.exit(0);
});
}
});
you could end a mongodb process using nodeJS on mac
1) save the script below to a script.js
'use strict'
const exec = require('child_process').execSync;
function killport(port) {
var processId = null
try {
processId = exec(`lsof -t -i:${port}`);
} catch (e) {
console.log("could not catch");
}
if (processId !== null) { // if exists kill
try{
if(exec(`kill ${processId}`)){
console.log("closed");
}
} catch(e){
console.log("error executing");
}
}
}
killport(27017);
2) run node script.js

Resources