Is it possible to get the parent process-id using Node.JS? I would like to detect if the parent is killed or fails in such a way that it cannot notify the child. If this happens, the parent process id of the child should become 1.
This would be preferable to requiring the parent to periodically send a keep-alive signal and also preferable to running the ps command.
You can use pid-file. Something like that
var util = require('util'),
fs = require('fs'),
pidfile = '/var/run/nodemaster.pid';
try {
var pid = fs.readFileSync(pidfile);
//REPLACE with your signal or use another method to check process existence :)
process.kill(pid, 'SIGUSR2');
util.puts('Master already running');
process.exit(1);
} catch (e) {
fs.writeFileSync(pidfile, process.pid.toString(), 'ascii');
}
//run your childs here
Also you can send pid as argument in spawn() call
I start Node.JS from within a native OSX application as a background worker. To make node.js exit when the parent process which consumes node.js stdout dies/exits, I do the following:
// Watch parent exit when it dies
process.stdout.resume();
process.stdout.on('end', function() {
process.exit();
});
Easy like that, but I'm not exactly sure if it's what you've been asking for ;-)
Related
I'm developing a desktop application using Electron framework and I've to use sqlite database for app data.
I decided to use better-sqlite3 because of:
Custom SQL function support (It's very important for me)
It's much faster than node-sqlite3 in most cases
It is simple to use.
It's synchronous API (in most cases I need to get data serialized)
but in some cases, when I perform a query that takes a while to response, the application UI won't responses to user until the query ends.
how can I run some db queries in another thread? or run them asyncronized (like node-sqlite3)?
sorry for bad english
Node allows you a separate process out-of-the-box. ( Threads are a different matter - alas no WebWorkers :( though you can prob find a thread add-on lib somwhere.
EDIT: Node has added worker_threads since I originally posted this answer. Haven't tried it yet / dunno if they work with better-sqlite.END EDIT
I've had the same issue as you - needing synchronous code to run without blocking the main thread and I used a child process. It was for better-sqlite too !
Problem is that how to handle io streams and sigints etc for control is not immediately obvious and differs depending on whether you're running on windows or posix.
I use a forked child process with silent option set to true to do the synchronous db work.
If you need control of that process or progress update reports back to your main process for your gui during sync ops ; I control/communicate with the child process by reading/writing on the child process stdin/out using fileSystem writeFileSync / readFileSync at various points in my child process code ( you can't use the normal inter-process comms api during sync ops as that's event driven and can't operate while synchronous code is running. Though you can mix and match the two types of io)
example of forked child process ;
//parent.js and child.js in same folder
//parent.js
process.on('exit', (code) => {
console.log(`Parent to exit with code: ${code}`);
});
const readLine = require("readline") ;
const cp = require('child_process');
var forkOptions = {
//execArgv:['--inspect-brk'], // uncomment if debugging the child process
silent:true // child gets own std pipes (important) whch are piped to parent
};
var childOptions = [] ;
const child = cp.fork(`./child.js`,childOptions,forkOptions);
//for messages sent from child via writeSync
const childChannel = readLine.createInterface({
input: child.stdout
}).on("line",function(input){
console.log("writeSync message received from child: " + input) ;
});
//for messages sent from child via process.send
child.on('message', (m) => {
console.log("process.send message received from child: " + m) ;
});
// Child.js
process.on('exit', (code) => {
console.log(`Child to exit with code: ${code}`);
});
const fs = require('fs');
function doSyncStuff(){
for(let i = 0 ; i < 20 ; i++){
//eg. sync db calls happening here
process.send(`Hello via process.send from child. i = ${i} \n`); // async commms . picked up by parent's "child.on" event
fs.writeFileSync(process.stdout.fd,`Hello via writeFileSync from child. i = ${i} \n`) ; // sync comms. picked up by parent's readLine listener ("process" here is the child )
}
}
doSyncStuff();
I have a few child processes of node, that depends from master. Every process is a program with some asynchronic logic. And i have to terminate this process when all will be done. But process not terminate by himself, cause there some listeners on it. Example:
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
let worker = cluster.fork();
worker.send(i);
}
} else {
process.once('message', msg => {
// here some logic
// and after this is done, process have to terminated
console.log(msg);
})
}
But process still working, even i using "once". I had tried to remove all of process listeners, but it still works. How i can terminate it?
Use module like
terminate
Terminate a Node.js Process based on the Process ID
A minimalist yet reliable (tested) way to Terminate a Node.js Process (and all Child Processes) based on the Process ID
var terminate = require('terminate');
terminate(process.pid, function(err, done){
if(err) { // you will get an error if you did not supply a valid process.pid
console.log("Oopsy: " + err); // handle errors in your preferred way.
}
else {
console.log(done); // do what you do best!
}
});
or
We can start child processes with {detached: true} option so those processes will not be attached to main process but they will go to a new group of processes. Then using process.kill(-pid) method on main process we can kill all processes that are in the same group of a child process with the same pid group. In my case, I only have one processes in this group.
var spawn = require('child_process').spawn;
var child = spawn('my-command', {detached: true});
process.kill(-child.pid);
For cluster worker processes, you can call process.disconnect() to disconnect the IPC channel with the master process. Having the IPC channel connected will keep the worker process alive.
I have an electron app that uses child_process.exec to run long running tasks.
I am struggling to manage when the user exits the app during those tasks.
If they exit my app or hit close the child processes continue to run until they finish however the electron app window has already closed and exited.
Is there a way to notify the user that there are process still running and when they have finished then close the app window?
All I have in my main.js is the standard code:
// Quit when all windows are closed.
app.on('window-all-closed', function() {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform != 'darwin') {
app.quit();
}
});
Should I be adding a check somewhere?
Thanks for your help
EDITED
I cannot seem to get the PID of the child_process until it has finished. This is my child_process code
var loader = child_process.exec(cmd, function(error, stdout, stderr) {
console.log(loader.pid)
if (error) {
console.log(error.message);
}
console.log('Loaded: ', value);
});
Should I be trying to get it in a different way?
So after everyones great comments I was able to update my code with a number of additions to get it to work, so am posting my updates for everyone else.
1) Change from child_process.exec to child_process.spawn
var loader = child_process.spawn('program', options, { detached: true })
2) Use the Electron ipcRenderer to communicate from my module to the main.js script. This allows me to send the PIDs to main.js
ipcRenderer.send('pid-message', loader.pid);
ipcMain.on('pid-message', function(event, arg) {
console.log('Main:', arg);
pids.push(arg);
});
3) Add those PIDs to array
4) In my main.js I added the following code to kill any PIDs that exist in the array before exiting the app.
// App close handler
app.on('before-quit', function() {
pids.forEach(function(pid) {
// A simple pid lookup
ps.kill( pid, function( err ) {
if (err) {
throw new Error( err );
}
else {
console.log( 'Process %s has been killed!', pid );
}
});
});
});
Thanks for everyones help.
ChildProcess emits an exit event when the process has finished - if you keep track of the current processes in an array, and have them remove themselves after the exit event fires, you should be able to just foreach over the remaining ones running ChildProcess.kill() when you exit your app.
This may not be 100% working code/not the best way of doing things, as I'm not in a position to test it right now, but it should be enough to set you down the right path.
var processes = [];
// Adding a process
var newProcess = child_process.exec("mycommand");
processes.push(newProcess);
newProcess.on("exit", function () {
processes.splice(processes.indexOf(newProcess), 1);
});
// App close handler
app.on('window-all-closed', function() {
if (process.platform != 'darwin') {
processes.forEach(function(proc) {
proc.kill();
});
app.quit();
}
});
EDIT: As shreik mentioned in a comment, you could also just store the PIDs in the array instead of the ChildProcess objects, then use process.kill(pid) to kill them. Might be a little more efficient!
Another solution. If you want to keep using exec()
In order to kill the child process running by exec() take a look to the module ps-tree. They exaplain what is happening.
in UNIX, a process may terminate by using the exit call, and it's
parent process may wait for that event by using the wait system call.
the wait system call returns the process identifier of a terminated
child, so that the parent tell which of the possibly many children has
terminated. If the parent terminates, however, all it's children have
assigned as their new parent the init process. Thus, the children
still have a parent to collect their status and execution statistics.
(from "operating system concepts")
SOLUTION: use ps-tree to get all processes that a child_process may have started, so that they
exec() actually works like this:
function exec (cmd, cb) {
spawn('sh', ['-c', cmd]);
...
}
So check the example and adapt it to your needs
var cp = require('child_process'),
psTree = require('ps-tree');
var child = cp.exec("node -e 'while (true);'", function () { /*...*/ });
psTree(child.pid, function (err, children) {
cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID })));
});
I'm trying to fork a node child process with
child_process.fork("child.js")
and have it say alive after the parent exits. I've tried using the detached option like so:
child_process.fork("child.js", [], {detached:true});
Which works when using spawn, but when detached is true using fork it just fails silently, not even executing the child.js.
I've also tried
var p = child_process.fork("child.js")
p.disconnect();
p.unref();
But child still dies when the parent does.
Any help or insight would be greatly appreciated.
EDIT:
Node Version: v5.3.0
Platform: Windows 8.1
Code:
//Parent
var child_process = require("child_process");
var p;
try{
console.log(1)
p = child_process.fork("./child.js")
console.log(2)
} catch(e){
console.log(e)
}
p.on('error', console.log.bind(console))
p.disconnect();
p.unref();
//To keep process alive
setTimeout(() => {
console.log(1);
}, 100000);
--
//Child
var fs = require("fs");
console.log(3);
fs.writeFileSync("test.txt", new Date().toString());
setTimeout(()=>{
console.log(1);
}, 100000);
I'm assuming you're executing your parent file from the command line, which is probably why it "appears" that the forked child is not executing. In reality when the parent process exits, the terminal stops waiting and thus prints a new line, waiting for your next command. This makes it seem like the child isn't executing, but trust me it is. Also there is no "detached" option for child_process.fork
Add some console.log() statements to your child process and you should see input printing in your terminal even after the parent has exited. If you don't it's because your child is prematurely exiting due to an error. Run your child process directly to debug it, before calling it from the parent.
Check out this quick example:
Hope this helps.
Here's my problem. I implemented a small script that does some heavy calculation, as a node.js module. So, if I type "node myModule.js", it calculates for a second, then returns a value.
Now, I want to use that module from my main Node.JS program. I could just put all the calculation in a "doSomeCalculation" function then do:
var myModule = require("./myModule");
myModule.doSomeCalculation();
But that would be blocking, thus it'd be bad. I'd like to use it in a non-blocking way, like DB calls natively are, for instance. So I tried to use child_process.spawn and exec, like this:
var spawn = require("child_process").spawn;
var ext = spawn("node ./myModule.js", function(err, stdout, stderr) { /* whatevs */ });
ext.on("exit", function() { console.log("calculation over!"); });
But, of course, it doesn't work. I tried to use an EventEmitter in myModule, emitting "calculationDone" events and trying to add the associated listener on the "ext" variable in the example above. Still doesn't work.
As for forks, they're not really what I'm trying to do. Forks would require putting the calculation-related code in the main program, forking, calculating in the child while the parent does whatever it does, and then how would I return the result?
So here's my question: can I use a child process to do some non-blocking calculation, when the calculation is put in a Node file, or is it just impossible? Should I do the heavy calculation in a Python script instead? In both cases, how can I pass arguments to the child process - for instance, an image?
I think what you're after is the child_process.fork() API.
For example, if you have the following two files:
In 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');
In 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));
});
Then to run main (and spawn a child worker process for the worker.js code ...)
$ node --version
v0.8.3
$ node main.js
received: PLEASE UP-CASE THIS STRING
It doesn't matter what you will use as a child (Node, Python, whatever), Node doesn't care. Just make sure, that your calculcation script exits after everything is done and result is written to stdout.
Reason why it's not working is that you're using spawn instead of exec.