Restart an external process from within a nodejs app (linux) - node.js

Say that I am running a process from the command line (NOT a nodejs app):
myProcess doSomething --withParam1
I am also running a nodejs app that connects to this process (rpc).
node myApp
myProcess will randomly silently fail to work properly without crashing and myApp will detect it. I need myApp to be able to restart myProcess (kill it and start it again). After I restarted myProcess, myApp will also restart itself using pm2 (I am already handling the pm2 restart part for the nodejs app - my issue is that I cannot use pm2 to restart myProcess since it is not a nodejs app). Also, I cannot change the code of myProcess since it is a 3rd party software.
How can I restart the external process from my nodejs app?

I ended up using process.kill to kill the process and nodejs child process to restart it.
To find the pid of the process before killing it, I used this:
const childProcess = require('child_process');
function printPid() {
childProcess.exec('pidof -s myProcess', function(error, stdout, stderr) {
if (error) {
console.log(error);
} else {
console.log(stdout);
}
});
}

Related

Node.js getting SIGINT from pm2

I'm trying to use pm2 to run my node app as a service.
Right now, starting and stopping the app works. However, I want to do a graceful shutdown.
My app already listens for SIGINT, shutdowns the server and then exits the process. However, trying to put pm2 to send the SIGINT, just causes the app to restart, like if pm2 was killing and starting it again.
This is how I create the process:
pm2 start server.js --name ProcessName --silent --kill-timeout 3000
Here's my app's code for listening the SIGINT:
process.on("SIGINT", function () {
//graceful shutdown
server.end().then(() => {
process.exit();
}).catch((err) => {
console.error(err);
});
});
Then to shutdown the app using pm2, I'm running:
pm2 sendSignal SIGINT ProcessName
Which, again, restarts the app.
Reading over pm2 docs, I found that pm2 will also send a shutdown event to the app, so I added:
process.on('message', function(msg) {
if (msg == 'shutdown') {
server.end().then(() => {
process.exit();
}).catch((err) => {
console.error(err);
});
}
});
Which isn't working either.
Any idea how to solve this?
Thanks!
If you haven't solved it yet...
Based on the information you provided, I assume you are running it on Windows.
Your app cannot catch SIGINT sent by PM2 on Windows.
shutdown message works on windows too, but it is sent only by gracefulReload command.
(update)
These are not complete solutions, but might be helpful (hopefully...)
sendSignal command calls process.kill() eventually, and some of these signals might work (haven't tried).
I also found the below method. This can gracefully shutdown a process without restarting only if autorestart option is turned off.
And then your clusters will not reload in case of an accident, so it might not be what you want though...
pm2 lets you send a custom message (reference).
Put the code below in a new file:
var pm2 = require('pm2');
var id = process.argv[2];
pm2.connect(() => {
pm2.sendDataToProcessId({
type: 'shutdown',
data:{some: 'data'},
id: id,
topic: 'some topic'
}, (err, res) => {
console.log('message sent');
pm2.disconnect();
if(err) throw err;
})
});
Modify the part that listens the shutdown message like below:
process.on('message', function(msg){
if(msg == 'shutdown' || msg.type == 'shutdown'){
// code to clean up
}
});
And run the first file with node with id of the cluster you want to shutdown as an argument.
The reason for extra msg.type == 'shutdown' in the condition is that pm2.sendDataToProcessId() requires the argument to be an object with those keys, and does not accept simple shutdown string.
In general pm2 stop is the right way to stop your application. However if you run appliation inside of the Docker you need to use pm2-runtime instead of pm2 which is a part of pm2 npm package and passes system SIGINT to all child processes. See http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs
Catching the sigint and exiting gracefully should work in your first example.
To actually stop the server, use pm2 stop instead of pm2 sendSignal SIGINT ProcessName.
See http://pm2.keymetrics.io/docs/usage/signals-clean-restart/

How do I restart a Node.js server internally in the script on global error?

I've been browsing around but to no success. I've found some npm packages like nodemon and forever but documentation doesn't explain how to call a restart inside the script properly.
I've found this code snippet on another question but I'm not using Express or other frameworks since the script is using a pulling service not a response one.
This is code I've made so far using internal Node.js dependencies but no luck.
'use strict'
process.on('uncaughtException', (error) => {
console.error('Global uncaughtException error caught')
console.error(error.message)
console.log('Killing server with restart...')
process.exit(0)
})
process.on('exit', () => {
console.log('on exit detected')
const exec = require('child_process').exec
var command = 'node app.js'
exec(command, (error, stdout, stderr) => {
console.log(`error: ${error.message}`)
console.log(`stdout: ${stdout}`)
console.log(`stderr: ${stderr}`)
})
})
setTimeout(() => {
errorTriggerTimeBomb() // Dummy error for testing triggering uncaughtException
}, 3000)
Just to note I'm running the server on Termux, a Linux terminal app for android. I know it's better to run from desktop but I'm always at a WiFi or mobile data area and that I don't like leaving my PC on overnight.
A typical restart using something like nodemon or forever would be triggered by calling process.exit() in your script.
This would exit the current script and then the monitoring agent would see that it exited and would restart it for you. It's the same principal as if it crashed on its own, but if you're trying to orchestrate it shutting down, you just exit the process and then the monitoring agent will restart it.
I have a home automation server that is being monitored using forever. If it crashes forever will automatically restart it. I also have it set so that at 4am every morning, it will call process.exit() and then forever will automatically restart it. I do this to prevent any memory leak accumulation over a long period of time and 30 seconds of down time in the middle of the night for my application is no big deal.

How to stop pm2 from killing detached child processes

pm2 is killing detached child processes on watch restart (ie which have been spawned with detached:true, stdio:'ignore', and child.unref().
Is there a way of telling pm2 not to kill the tree of child processes on restart?
The answer was to put the following in the ecosystem file (main section for app, not under the watch settings):
"treekill": false
I ended up using
pm2 restart myapp --no-treekill
and
pm2 stop myapp --no-treekill
I restart my nodejs app from within using the pm2 API. Here is the function I use so that detached child processes are not killed (notice the treekill: false option).
function restartPm2() {
pm2.connect(function(err) {
if (err) {
console.error("PM2 FAILED TO CONNECT:", err);
} else {
pm2.restart('myapp.js', { treekill: false }, function() {});
}
});
pm2.disconnect();
}

How to Restart nodeJS screen app without reboot PC

I trying to restart nodejs app which is running in background screen app.
But here i can't do these without reboot my PC. I used forever module but it's start when i reboot my PC but I actually want one button on web-page and when I click on that automatically start node app without restart my PC.
Any One have iDEA about these please let me guide what to Do ?
NOTE : without reboot my system working
You can execute commands from nodejs like this :
nodejs
var child_process = require('child_process');
child_process.exec('forever restart', function callback(error, stdout, stderr) {
// console.log(stdout);
});

How can I restart a Node.js app from within itself (programmatically)?

How can I create an app that can restart itself? I want to create an app that sets up a web-admin which can restart itself. Is this possible? If so, how? I was thinking this might be possible with the process global variable that is built into node.
LK"I
It is possible without external dependencies:
console.log("This is pid " + process.pid);
setTimeout(function () {
process.on("exit", function () {
require("child_process").spawn(process.argv.shift(), process.argv, {
cwd: process.cwd(),
detached : true,
stdio: "inherit"
});
});
process.exit();
}, 5000);
source : https://gist.github.com/silverwind/d0802f7a919ae86ff25e
I have run Forever several times and it is easy to get started with. Check it out at: https://github.com/nodejitsu/forever
I know it's a little late to reply however I had a similar requirement. I wanted to restart my node process whenever I made a configuration change. I'm using pm2 to manage my node processes so it turned out to be really easy.
After making a configuration change, i execute process.exit() from within the node process. As far as I can see, the process exits then pm2 restarts the process fine.
Not sure yet if there are any side effects but it seems to be working fine for me right now.
you can run your app using child process and manipulate it how needed:
https://nodejs.org/api/child_process.html
use forever, pm2 or whatever thing to restart after death and kill itself with process.exit() https://nodejs.org/api/process.html
Not from the process itself but it might be useful to people that land on here.
I add it to systemd of Linux and it starts up on network.target logs the console to /var/logs/<app>.log and it restarts on failure. So you can just force a process.exit on it.
sudo touch /lib/systemd/system/<app>.service
sudo tee -a /lib/systemd/system/<app>.service > /dev/null <<EOT
[Unit]
Description=<app>
After=network.target
[Service]
Type=simple
User=$USER
ExecStart=/bin/node --prefix /home/$USER/path/to/app
Restart=on-failure # or always
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=<app>
[Install]
WantedBy=multi-user.target
EOT
sudo touch /etc/rsyslog.d/<app>.conf
sudo tee -a /etc/rsyslog.d/<app>.conf > /dev/null <<EOT
if $programname == '<app>' then /var/log/<app>.log
& stop
EOT
sudo systemctl enable <app>
sudo systemctl daemon-reload
sudo systemctl restart rsyslog
sudo systemctl start <app>
i know the question is a little old but it may help someone later :
i would suggest to use nodeJS Cluster & Worker for this purpose!
const cluster = require('cluster');
if (cluster.isMaster ?? cluster.isPrimary) {
cluster.fork();
cluster.on("exit", (worker, code) => {
console.log(`[master] worker #${worker.id} down, restarting\n`);
cluster.fork();
});
process.on("SIGINT", () => { });
} else {
console.log(`\nnew worker #${cluster.worker.id}\n`);
process.on("SIGINT", () => {
console.log(`[worker#${cluster.worker.id}] SIGINT received! dying gracefully!!\n`);
process.exit(0);
});
}
try running it with nodejs and hitting the ctrl+c combination.
it will just restart with the new code running.
you can kill the master with sending any signal other than SIGINT
create file nodemon.sh
#!/usr/bin/env bash
while true; do
sleep 20
echo "// nodemon $(date)" >config.js
done
permition sudo chmod +x nodemon.sh
run it
./nodemon.sh
Yes, upstart will restart your process without a nodemon.
npm install -g nodemon
sudo nodemon server.js
nodemon will watch the files in the directory that nodemon was started, and if they change, it will automatically restart your node application.

Resources