Express server doesn't close - node.js

I'm creating an Express server with reloadable endpoints.
To make this possible I created an endpoint for such a purpose.
But when I call server.close() on the Express's HTTP server it still continues listening, while the server.listening says otherwise, it still is.
Here is a simplified version of my script (Not working fully, but you get the gist):
class simpleServer {
constructor() {
let express = require('express');
this.app = express();
this.app.get('/reload', this.reload);
this.server = this.app.listen(3000);
}
reload(req, res) {
console.log('Closing server');
this.server.close(function() {
console.log('Closed server');
});
// Re-init & stuff
res.json({
message: 'Reloaded'
});
}
}
let server = new simpleServer();
When I call the endpoint, the server will output 'Closing server', but the 'Closed server' takes a long time to be called (5 minutes). And when I reload the page, it still works, while the server.listening is equal to false.
I'm using Node.js version 6.0.0 with Express version 4.14.0.
Some updates:
I fixed the issue by calling req.destroy() after sending the response, does this have any side-effects tho?
A cleaner fix would be keeping a record of current connections and closing those in the reload function instead of closing them instantly. This will probably be less heavy if you have a higher load.

When you call .close(), it only stops accepting new connections, it does not terminate existing connections.
The reason it may take some time to actually close is if there are existing connections that have set Connection: keep-alive in case of more requests.

You can use process.exit().
Or you can try
this.server.close(function() {
console.log('Closed server');
})();

Related

next.js and mongodb coherence?

I googled a lot but still have no clear solution to my issue.
Connecting to MongoDB, usually you establish a connection and after the job is done you close it.
Since next.js (and probably node.js) is single threaded. Sometimes it happens that there are two requests processed async while one request established the connection to the database, the otherone is closing the exact same connection. So the first request runs into an Topology closed exception. I have the feeling that the mongodb driver client is shared.
Is there something I did not understood correct in this?
try {
await client.connect()
const database = client.db("test")
const collection = database.collection("test")
const newDataset = await collection.insertOne({})
return newDataset.insertedId.toString()
} finally {
await client.close();
}
As in the comments stated, ive seen a lot of examples & questions here on stackoverflow where in each received request (example below) a database connection is established. This has no benefits and is "bad" because it just takes time and makes no sense. E.g:
app.get("/", (req, res) => {
MongoClient.connect("...", (err, client) => {
// do what ever you want here
client.close();
});
});
If you application needs a database connection, establish the connection "in the startup phase" and keep the connection open. There is no reason to open and close the database connection for each request.
const mongodb = require("monogdb");
const express = require("express");
const app = express();
// some custom init stuff
// e.g. require your route handler etc.
mongodb.MongoClient("...", (err, client) => {
// do what ever you want with the db connection now
// e.g. monkey patch it, so you can use it in other files
// (There are better ways to handle that)
mongodb.client = client;
// or the better way
// pass it as function parameter
require("./routes")(app, client);
app.listen(8080, () => {
console.log("http server listening");
});
});
As you can see in the code above, we first create a database connection and then do other stuff. This has some advantages:
If your credentials are invalid, your application is not externeal reachable because the http server is not started
You have a single connection for all requests
Database queries are potential faster because you dont have to wait to establish first a db connection
NOTE: the code above was "inline coded" here and is not tested.
But i think its illustrated the concept behind my statement.

Websocket request sometimes doesn't work after connection establishment

I have a Node.js script which is supposed to regularly access a SailsJS application via a socket connection. Client and server run on physically different machines on different networks. The SailsJS application is proxied behind nginx. That works in general. However, at random times, the connection is established but the first post request within the websocket connection never reaches its destination.
The code looks basically like this:
var socketIOClient = require('socket.io-client');
var sailsIOClient = require('sails.io.js');
var io = sailsIOClient(socketIOClient);
io.sails.url = 'https://foo.foo:443';
io.sails.rejectUnauthorized = false;
io.socket.on('connect', function() {
console.log("Connected!")
io.socket.post('/someroute', { someOptions: "foo" } ,
function(data) {
console.log(data);
});
});
io.socket.on('disconnect', function(){
console.log("Disconnected!");
});
io.socket.on('connect_error',function () {
console.log("connect_error!");
});
In case of a failure, simply nothing happens after console.log("Connected!"). Nothing appears in nginx's logs (in contrast to successful cases), the callback of io.socket.post never gets executed.
The most important question for me is: At which side is the problem? Client or server?
How can I debug this and narrow down the problem? Could it be a networking issue? Or something wrong the configuration, implementation or with the script itself?

How to do graceful stop for koajs server?

There are a lot of examples of graceful stop for expressjs, how can I achieve the same for koajs?
I would like to disconnect database connections as well
I have a mongoose database connection, and 2 oracle db connection (https://github.com/oracle/node-oracledb)
I created an npm package http-graceful-shutdown (https://github.com/sebhildebrandt/http-graceful-shutdown) some time ago. This works perfectly with http, express and koa. As you want to add also your own cleanup stuff, I modified the package, so that you now can add your own cleanup function, that will be called on shutdown. So basically this package handles all http shutdown things plus calling your cleanup function (if provided in the options):
const koa = require('koa');
const gracefulShutdown = require('http-graceful-shutdown');
const app = new koa();
...
server = app.listen(...); // app can be an express OR koa app
...
// your personal cleanup function - this one takes one second to complete
function cleanup() {
return new Promise((resolve) => {
console.log('... in cleanup')
setTimeout(function() {
console.log('... cleanup finished');
resolve();
}, 1000)
});
}
// this enables the graceful shutdown with advanced options
gracefulShutdown(server,
{
signals: 'SIGINT SIGTERM',
timeout: 30000,
development: false,
onShutdown: cleanup,
finally: function() {
console.log('Server gracefulls shutted down.....')
}
}
);
I have answered a variation of "how to terminate a HTTP server" many times on different node.js support channels. Unfortunately, I couldn't recommend any of the existing libraries because they are lacking in one or another way. I have since put together a package that (I believe) is handling all the cases expected of graceful HTTP server termination.
https://github.com/gajus/http-terminator
The main benefit of http-terminator is that:
it does not monkey-patch Node.js API
it immediately destroys all sockets without an attached HTTP request
it allows graceful timeout to sockets with ongoing HTTP requests
it properly handles HTTPS connections
it informs connections using keep-alive that server is shutting down by setting a connection: close header
it does not terminate the Node.js process
Usage with Koa:
import Koa from 'koa';
import {
createHttpTerminator,
} from 'http-terminator';
const app = new Koa();
const server = app.listen();
const httpTerminator = createHttpTerminator({
server,
});
await httpTerminator.terminate();
To make sure the Oracle DB connections are closed nicely, you can use a connection pool and call pool.close() with a drainTime of 0 or greater. This will let the app relatively cleanly interrupt any operation that is currently using a connection. It allows freeing the DB end of the connections without the DB waiting for whatever timeout period to expire before it cleans itself up. Even with two connections this is a solution I'd look at, since it doesn't matter that the pool is small. You may need to set the Oracle Net out-of-band break detection as well, see Connections and High Availability.
Modern versions of node have support for AbortController, so no need for external libraries. A Simple example:
const app = new Koa();
const server = http.createServer(app.callback());
const controller = new AbortController();
server.listen({
host: 'localhost',
port: 80,
signal: controller.signal
});
// middleware... etc.
app.use(async (ctx) => {
ctx.body = 'Hello World';
});
// Later, when you want to close the server.
controller.abort();

node process doesn't exit after firebase once

Using node.js with the npm firebase.
var firebase = require('firebase');
var blahFirebase = new firebase('https://myfirebase.firebaseIO.com/blah');
blahFirebase.once('value', function (snapshot) {
//
});
Why does node not exit when it is done reading the data?
In the new Firebase API you should use firebase.app.App.delete() to free the resources its holding. For example:
var app = firebase.initializeApp({ ... });
var db = firebase.database();
// Do something
app.delete(); // Release resources
Do not use process.exit() since it will stop the entire process (which is not what you would usually want).
My case is using firebase admin,
const admin = require('firebase-admin');
and I can end node process by
return admin.app().delete();
Update
Note that this is no longer applicable. Node.js will no longer hang when using once(), although it will be held open as long as there are active listeners subscribed to the remote server.
Original
The Firebase process opens sockets to the server and establishes listeners for incoming data on those connections. Just like a node web server, awaiting incoming HTTP connections, this holds the process open.
To end the process, you can simply utilize process.exit() from inside the callback:
blahFirebase.once('value', function (snapshot) {
//
process.exit();
});
setTimeout(()=> {
process.exit(1);
}, 1000);
Dunno why, but solved the problem.

Change port without losing data

I'm building a settings manager for my http server. I want to be able to change settings without having to kill the whole process. One of the settings I would like to be able to change is change the port number, and I've come up with a variety of solutions:
Kill the process and restart it
Call server.close() and then do the first approach
Call server.close() and initialize a new server in the same process
The problem is, I'm not sure what the repercussions of each approach is. I know that the first will work, but I'd really like to accomplish these things:
Respond to existing requests without accepting new ones
Maintain data in memory on the new server
Lose as little uptime as possible
Is there any way to get everything I want? The API for server.close() gives me hope:
server.close(): Stops the server from accepting new connections.
My server will only be accessible by clients I create and by a very limited number of clients connecting through a browser, so I will be able to notify them of a port change. I understand that changing ports is generally a bad idea, but I want to allow for the edge-case where it is convenient or possibly necessary.
P.S. I'm using connect if that changes anything.
P.P.S. Relatively unrelated, but what would change if I were to use UNIX server sockets or change the host name? This might be a more relevant use-case.
P.P.P.S. This code illustrates the problem of using server.close(). None of the previous servers are killed, but more are created with access to the same resources...
var http = require("http");
var server = false,
curPort = 8888;
function OnRequest(req,res){
res.end("You are on port " + curPort);
CreateServer(curPort + 1);
}
function CreateServer(port){
if(server){
server.close();
server = false;
}
curPort = port;
server = http.createServer(OnRequest);
server.listen(curPort);
}
CreateServer(curPort);
Resources:
http://nodejs.org/docs/v0.4.4/api/http.html#server.close
I tested the close() function. It seems to do absolute nothing. The server still accepts connections on his port. restarting the process was the only way for me.
I used the following code:
var http = require("http");
var server = false;
function OnRequest(req,res){
res.end("server now listens on port "+8889);
CreateServer(8889);
}
function CreateServer(port){
if(server){
server.close();
server = false;
}
server = http.createServer(OnRequest);
server.listen(port);
}
CreateServer(8888);
I was about to file an issue on the node github page when I decided to test my code thoroughly to see if it really is a bug (I hate filing bug reports when it's user error). I realized that the problem only manifests itself in the browser, because apparently browsers do some weird kind of HTTP request keep alive thing where it can still access dead ports because there's still a connection with the server.
What I've learned is this:
Browser caches keep ports alive unless the process on the server is killed
Utilities that do not keep caches by default (curl, wget, etc) work as expected
HTTP requests in node also don't keep the same type of cache that browsers do
For example, I used this code to prove that node http clients don't have access to old ports:
Client-side code:
var http = require('http'),
client,
request;
function createClient (port) {
client = http.createClient(port, 'localhost');
request = client.request('GET', '/create');
request.end();
request.on('response', function (response) {
response.on('end', function () {
console.log("Request ended on port " + port);
setTimeout(function () {
createClient(port);
}, 5000);
});
});
}
createClient(8888);
And server-side code:
var http = require("http");
var server,
curPort = 8888;
function CreateServer(port){
if(server){
server.close();
server = undefined;
}
curPort = port;
server = http.createServer(function (req, res) {
res.end("You are on port " + curPort);
if (req.url === "/create") {
CreateServer(curPort);
}
});
server.listen(curPort);
console.log("Server listening on port " + curPort);
}
CreateServer(curPort);
Thanks everyone for the responses.
What about using cluster?
http://learnboost.github.com/cluster/docs/reload.html
It looks interesting!

Resources