How to reload Node.JS app without losing current open requests? - node.js

I'm using pm2 to reload my app but in my test the active requests are cancelled by the reload.
I tested by making an endpoint with an await of 10 seconds, requesting a response to this endpoint with Insomnia and then, before the 10 seconds await completes, reloading the app with pm2 reload . But what happens is that the pm2 reload stops the Insomnia request, which finishes as "Error: Server returned nothing (no headers, no data)".
Am I doing something wrong? Was not pm2 supposed to identify current running requests on await state? It could be a real production request where the app was waiting for a database response.

You can catch the SIGTERM signal from within your node.js/express application:
process.on('SIGTERM', () => {
console.info('SIGTERM signal received.');
console.log('Close http server.');
server.close(() => {
console.log('Http server closed.');
// You can close here other things that needs to, for example a mongodb/mongoose connection
mongoose.connection.close(false, () => {
console.log('MongoDb connection closed.');
process.exit(0);
});
});
});

Related

Socket.io client behavior when server is unreachable

I was wondering what is the default behavior when socket.io-client can't connect to the server and no callback is provided on the error.
Does the client indefinitely try to reconnect until it can reach the server?
I noticed that If I run this code on client before launching the server. As soon as the latter is started it receives the 'doSomethig' evnt.
socket.on('connect', function () {
socket.emit('doSomething', data);
socket.destroy();
});
How can I prevent the server to receive data emitted before it was started?
socket.on('connect_error', function () { socket.destroy(); });

Gracefully shutdown in node.js/express with async jobs

I am trying to make gracefully shutdown in node.js using express 4.x http server.
Closing express server is easy but what worries me is that we have a lot of async jobs. Example of the flow :
Receive request
Do some stuff
Send response back to the client
In background continue to do some async stuff related to that request like making another request to some third part service
Receive response from third part service and save response to database etc.
Finish
So if I make my gracefully shutdown code like this :
process.on('SIGTERM', function () {
serverInstance.close(function(){
closeConnectionToDatabases(function(){
process.exit(0);
})
});
// shutdown anyway after some time
setTimeout(function(){
process.exit(0);
}, 8000);
});
How can I be sure that everything goes ok if SIGTERM has happened between first and second step in flow explained above? What about fourth, fifth and sixth step? Is there any nice way to handle this or it is just about manually watch to all requests going from your service in async way and wait for them?
Thanks,
Ivan
process.exit() will terminate node.js process immediately, without waiting for all aync tasks to finish.
If you want a truly graceful shutdown, you should close all resources (all open connections and file descriptors) manually, instead of calling process.exit(). In this case node.js will terminate immediately after finishing all pending async tasks.
So, just close all database connections and other i/o resources:
process.on('SIGTERM', function () {
serverInstance.close(function(){
closeConnectionToDatabases(function(){
// now node.js should close automatically
})
});
// shutdown anyway after some time
setTimeout(function(){
process.exit(0);
}, 8000);
});
Here's a better option:
Instead of using setTimeout to wait for all the async jobs to finish, we can create a new Promise, and resolve it when the async jobs are completed. Then after the promise is resolved, we can exit the process.
process.on('SIGTERM', () => {
new Promise((resolve) => {
serverInstance.close(async () => {
await closeConnectionToDatabases();
resolve();
});
}).then(() => process.exit(0))
});
Hope it helps you :)

Error connecting mariadb - node.js?

I am using MariaDB in my node.js application. I am having the following code
var nodeMaria = require('node-mariadb');
var connection = nodeMaria.createConnection({
driverType: nodeMaria.DRIVER_TYPE_HANDLER_SOCKET,
host:'localhost',
port:9998
});
connection.on('error', function(err){
console.log(err);
process.exit(1);
});
connection.on('connect', function(){
console.log("mariadb connected");
});
Problem
After connecting the db, It is logging "mariadb connected".
After that Application is breaking without throwing any error.
Note: I had handled the error in connection connection.on('erorr',function(){});
Any help will be great.
If the application is closing, it doesn't necessarily mean that an error has occurred with connecting to MariaDB.
In fact, if there isn't anything keeping a node application explicitly open, it just closes after execution of the code.
What keeps a node application open? Event listeners. If you have an event listener listening for events, the node application doesn't close after finishing code execution. For example, if you have a http.listen command, which starts the web server and starts listening for incoming HTTP connections.

Efficient HTTP shutdown with keepalives?

This Node.js server will shutdown cleanly on a Ctrl+C when all connections are closed.
var http = require('http');
var app = http.createServer(function (req, res) {
res.end('Hello');
});
process.on('SIGINT', function() {
console.log('Closing...');
app.close(function () {
console.log('Closed.');
process.exit();
});
});
app.listen(3000);
The problem with this is that it includes keepalive connections. If you open a tab to this app in Chrome and then try to Ctrl+C it, it won't shutdown for about 2 minutes when Chrome finally releases the connection.
Is there a clean way of detecting when there are no more HTTP requests, even if some connections are still open?
By default there's no socket timeout, that means that connections will be open forever until the client closes them. If you want to set a timeout use this function: socket.setTimeout.
If you try to close the server you simply can't because there are active connections, so if you try to gracefully shutdown the shutdown function will hang up. The only way is to set a timeout and when it expires kill the app.
If you have workers it's not as simple as killing the app with process.exit(), so I made a module that does extacly what you're asking: grace.
You can hack some request tracking with the finish event on response:
var reqCount = 0;
var app = http.createServer(function (req, res) {
reqCount++;
res.on('finish', function() { reqCount--; });
res.end('Hello');
});
Allowing you to check whether reqCount is zero when you come to close the server.
The correct thing to do, though, is probably to not care about the old server and just start a new one. Usually the restart is to get new code, so you can start a fresh process without waiting for the old one to end, optionally using the child_process module to have a toplevel script managing the whole thing. Or even use the cluster module, allowing you to start the new process before you've even shut down the old one (since cluster manages balancing traffic between its child instances).
One thing I haven't actually tested very far, is whether it's guaranteed safe to start a new server as soon as server.close() returns. If not, then the new server could potentially fail to bind. There's an example in the server.listen() docs about how to handle such an EADDRINUSE error.

How to check if connection was aborted in node.js server

I'm making some long polling with node.js.
Basically, node.js server accepts request from the user and then checks for some updates. If there're no updates, it will check them after the timeout.
But what if user has closed his tab, or went to another page? In my case, the script continues working.
Is there a way in node.js to check or detect or to catch an event when user has aborted his request (closed the connection)?
You need to use req.on('close', function(err) { ... }); instead of req.connection.on('close', function(err) { ... });
There is a very important distinction. req.on() adds a listener to this request while req.connection.on(), you add a listener to the (keep-alive) connection between the client and the server. If you use req.connection.on(), every time the client re-uses a connection, you add one more listener to the same connection. When the connection is finally aborted, all listeners are fired.
Function scoping typically keeps you safe from this screwing up your server logic, but it's a dangerous thing nevertheless. Fortunately at least NodeJS 0.10.26 is smart enough to warn the user of this:
(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace:
at Socket.EventEmitter.addListener (events.js:160:15)
at Socket.Readable.on (_stream_readable.js:689:33)
...
Thanks to Miroshko's and yojimbo87's answers I was able to catch the 'close' event, but I had to make some additional tweaks.
The reason why just catching 'close' event wasn't fixing my problem, is that when client sends the request to the node.js server, the server itself can't get information if the connection is still open until he sends something back to the client (as far as I understood - this is because of the HTTP protocol).
So, the additional tweak was to write something to the response from time to time.
One more thing that was preventing this to work, is that I had 'Content-type' as 'application/json'. Changing it to 'text/javascript' helped to stream 'white spaces' from time to time without closing the connection.
In the end, I had something like this:
var server = http.createServer(function(req,res){
res.writeHead(200, {'Content-type': 'text/javascript'});
req.connection.on('close',function(){
// code to handle connection abort
});
/**
* Here goes some long polling handler
* that performs res.write(' '); from time to time
*/
// some another code...
});
server.listen(NODE_PORT, NODE_LISTEN_HOST);
My original code is much bigger, so I had to cut it a lot just to show the sensitive parts.
I'd like to know if there are better solutions, but this is working for me at the moment.
Is there a way in node.js to check or detect or to catch an event when
user has aborted his request (closed the connection)?
You can try to use http.ServerRequest close event. Simple example:
var http = require("http"),
util = require("util");
var httpServer = http.createServer(function(req, res) {
util.log("new request...");
// notify me when client connection is lost
req.on("close", function(err) {
util.log("request closed...");
});
// wait with response for 15 seconds
setTimeout(function() {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write("response");
res.end();
util.log("response sent...");
}, 15000);
});
httpServer.listen(8080);
util.log("Running on 8080");
I'm using Express.js (~4.10.6) and the following code is working fine for me:
//GET Request:
app.get('/', function(req, res){
req.on('close', function(){
console.log('Client closed the connection');
});
});
As soon as I close the browser's tab, the browser closes the connection, and the callback function gets executed as expected.
Seems that your question is very similar to this one:
NodeJS HTTP request connection's close event fired twice
try
request.connection.on('close', function () {
...
});

Resources