Handling database connection errors with Express, Mongoose, and Passport - node.js

I'm building a small web application using Node.js, Express, Mongoose, and Passport. Everything is working, but I'm trying to make the application fail gracefully if the MongoDB user database is not available. The application makes a database call every time it deserializes the user out of the session, so I can't do much if the database is down. I just want to display a general error page to the user and recover if/when the database is back up.
Right now, in my local implementation, if I take down the MongoDB server (by just hitting CTRL-C) and then try to, say, reload a page with authentication, sometimes I get my global error page but mostly the application just hangs without generating any errors or console logs (despite the addition of multiple console.log() statements at key failure points, see below) and continues to hang on all future requests. If I then restart the MongoDB server, the application doesn't recover.
The complete source code is here but select code snippets are below.
Mongoose connection:
mongoose.connect(mongodbURI, mongodbConnectOptions);
// Log database events to the console for debugging purposes
mongoose.connection.on('open', function () {
console.log("Mongoose open event");
});
mongoose.connection.on('close', function () {
console.log("Mongoose close event");
});
mongoose.connection.on('connected', function () {
console.log("Mongoose connected event");
});
mongoose.connection.on('disconnected', function () {
console.log("Mongoose disconnected event");
});
mongoose.connection.on('error',function (err) {
console.log("Mongoose error event:");
console.log(err)
});
The Passport deserializeUser() call:
passport.deserializeUser(function(id, done) {
console.log("Attempting to deserialize user")
User.findById(id, function(err, user) {
if (err) console.log("Database error inside deserializeUser()");
done(err, user);
});
});
The global error handler (installed at the end of the Express stack):
var errorHandler = function(err, req, res, next) {
console.log("Error caught by Express error handler")
console.log(err);
res.status(500);
res.render('error', { error: err });
}
app.use(errorHandler);
I think this is probably related to this question, but I'm specifically trying to handle the case when the connection is completely lost (because the database is down). Suggestions?

Related

MongoClient doesnt trigger callback in case of error

MongoClient.connect(this._config.connectionString, {
useNewUrlParser: true,
useUnifiedTopology: true,
}, (err, db) => {
if (err) {
console.log(`error on connect : ${err}`);
return console.dir(err);
}
console.log('We are connected');
this._client = db;
});
This piece helps me connect to mongodb running locally, and works fine when DBserver is up and running. But if i stop db server and then try to execute this...it doesnt call the call back. Is there a way i can get call back in case of DB is down or not reachable?
below code doesnt get call back, in case of future DB errors.
this._client.on('error', args => this.onError(args));
Because of this issue of not getting call backs, in case of any severe errors...my server goes down without showing any error.

Mongoose connection printing out both console.log when mongo server not running

I have a mongoose connection to a mongodb server. When the server is running and it tries to connect it works fine and only prints out the single statement to the console. But when I haven't turned the mongo server on yet it prints both statements in the order they are in the code. I know this is not a huge error but would like to not have the health check show up as 'up' when the server is actually down.
Mongoose connection code:
mongoose.connect(config.db, {autoReconnect: true}, () => console.log('MongoDB has connected successfully.'));
mongoose.connection.on('error', function() {
console.error('MongoDB Connection Error. Make sure MongoDB is running.');
});
The connect callback receives an error parameter you can check:
mongoose.connect(config.db, {autoReconnect: true}, (err) => {
if (!err) console.log('MongoDB has connected successfully.');
});
You can also separately handle the 'connect' event in the same way you're handling the 'error' event:
mongoose.connection.on('connect', function() {
console.error('MongoDB has connected successfully');
});

"Error: Can't set headers after they are sent" in Express app with Node

I am new to Express and Node, and when testing a protected REST endpoint in my app using Advanced REST Client the data is returned from the endpoint to the Client as expected, however the console logs
"Error: Can't set headers after they are sent"
which stops the server. Searching here on SO, this seems to occur when sending more than one response but I don't see that in my code:
router.get('/books', userAuthenticated, function (req, res, next) {
Book.find({}, function(err, docs){
if(err) {
res.send(err)
} else {
res.send(docs);
// next();
// return;
}
})
});
Is this error expected when sending a request/response to/from the Client or am I missing something in handling the error on the server?
Express is a node.js server that features a concept called "middleware", where multiple layers of code get a chance to operate on a request.
In that case, not only do you need to check that your function is not sending back a response twice, but you have to check that other middleware are not sending back a response as well.
In your case, the code indicates that middleware called "userAuthenticated" is being invoked before this function. You should check if that middleware is already sending a response.
I don't think the problem was in the middleware. It looks like I was calling done() twice in passport deserialize. I commented out the first instance and the problem disappeared in all my routes. Although, I am not sure if I should comment out the first or second instance but I'll work on that next.
passport.deserializeUser(function(obj, done) {
console.log(obj);
Account.findById(obj, function(err, user) {
console.log(user);
//done(err, user);
});
return done(null, obj);
});

Disconnect PostgreSQL when client goes to new page

I'm trying to build a real time web page and use postgreSQL as my database. I use node.js and express to build backend stuff. Since this is a real time webpage and needs to update information very frequently, I keep a long connection with postgreSQL, which looks like:
app.get('/:A/:B', function(req,res){
var A = req.params.A;
var B = req.params.B;
var client = new pg.Client(config[A][B]);
client.connect(function(err){
if (err) {
console.log("Error occurred when try to connect the database",err);
}
else {
console.log("Connected to the database");
}
});
Do some queries with current database connection...
}
The problem is, when I change the value of A and B in browser and try to connect to a new database, I didn't disconnect with the old one so the info on my page are still from the old database. I'm new to node and web development. Can anyone let me know how to disconnect with the old database when client try to go to a new url?
I think is not good way to create connection for each request. If size of A-B variants is limited then create of connection pool on start is better.
app.get('/:A/:B', function(req, res, next){ // next to forwarding error
var A = req.params.A;
var B = req.params.B;
var client = new pg.Client(config[A][B]);
client.connect(function(err){
if (err)
return next(err); // go to error-middleware
console.log("Connected to the database");
// Do some queries with current database connection...
// Keep it mind that they're also asynchronous, so better way is use promises or async (https://github.com/caolan/async)
client.end(function (err) {
if (err)
next(err);
});
});
}
// Error middleware
app.use(function(err, req, res, next) {
console.log(req.url, err.message);
})

Nodejs inserting data to mongodb. It takes too much time

Hi i am developing nodejs application. I am inserting data to mongodb but my page always in 'loading' mode. But strange thing is my data inserted to mongodb immediately but page load not stopping. My code is shown below:
app.post('/Management/Post/New',function(req, res){
new Post({
title:req.body.post.title,
body:req.body.post.body,
keywords:req.body.post.keywords
}).save(function (err, docs){
if(err) {
return res.render(__dirname + "/views/createpost", {
title: 'Yeni Gönderi Oluştur',
stylesheet: 'postcreate',
error: 'Gönderi oluşturulurken bir hata ile karşılaşıldı'
});
}
console.log('Gönderi oluşturuldu');
});
});
Have no idea.
You only send a response when there is an error. If there's no error, you server never sends anything back: that's why the page seems to always be loading.
You need to send a response when you have no error, like this:
.save(function (err, docs){
if(err) { // Executed when there was an error with Mongo
return res.render(...);
} else { // Executed when everything is fine
return res.render(...);
}
});
You aren't handling the success scenario except for a console.log. You need a res.render() or res.redirect() on success, not just error

Resources