node.jsexpressnode.js-connectconnect-mongo

Handle database error when using connect-mongo


I've got a fairly standard connect-mongo setup

mongoose is initialised / connected prior to this

app.use(express.session({
    secret: "sfdgsdgsdfg",
    store: new MongoSessionStore({db: mongoose.connection.db})
}));

This works fine.

However - Assuming my mongodb connection suddenly dies (stop mongod locally in the example below) - the next time I try to hit a route, my express app crashes too -

Error: failed to connect to [localhost:27017] at null. (/Users/alex/Projects/MyProject/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:540:74) at emit (events.js:106:17) at null. (/Users/alex/Projects/MyProject/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:140:15) at emit (events.js:98:17) at Socket. (/Users/alex/Projects/MyProject/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:478:10) at Socket.emit (events.js:95:17) at net.js:440:14 at process._tickCallback (node.js:419:13)

Is there a way to handle this error and (For example) redirect to a /error route? (Obviously one that doesn't require session!)

EDIT

So now, I'm creating a separate mongoose connection.

I then use the on('error' to listen for errors

...this is where I'm getting stuck - The process still dies because re-throwing the err doesn't pass it into the express error handler...

var sessionDbConnection = mongoose.createConnection(config.sessionDb);

sessionDbConnection.on('error', function(err) {
    console.log('oops');
    throw err; //instead of re-throwing the error, i think i need to pass it to the error handler below??
})

app.use(express.session({
    secret: "sfdgsdgsdfg",
    store: new MongoSessionStore({db: sessionDbConnection.db})
}));

app.use(function(err, req, res, next) {
    res.render('error', err); //just for testing
});

Solution

  • Setup a general error handler at the end of your using chain ...

    //function must accept 4 arguments
    app.use(function(err, req, res, next) {
      //use accepts to determin if you should return json, html, image?
      //render the appropriate output.
    });
    

    Also, have your handlers and other modules accept three parameters (req, res, next) in the case of an error, return next(err) typically you will want to optionally use a .code property to match up your http response code to the one matching the error. using 4xx for input errors, 5xx for server errors etc.

    Also, if you want to handle the general case...

    process.on('uncaughtException', function(err) {
      console.error('Caught exception: ' + err);
      console.error(err.stack);
    
      //interrogate the error, if it's something you can recover from, let it be.
      //if the exception is fatal, exit with prejudice
      setTimeout(process.exit.bind(process, 666), 1000); //exit in a second
    });
    

    This will handle your specific case, but you should only allow the process to keep running if its' something that should recover on its' own.


    In response to your edit... you could have a global variable that changes when you get a DB error... unfortunately, this error doesn't necessarily happen in the context of an http request.. it could happen before/during/after ... in this way, you cannot know.

    If you are using a client that will re-connect on failure, then that will alleviate some issues. The best you can do, is keep track of this variable, serve errors to all requests.. then restart your process.

    There are lots of modules from pm2 to forever that will help you with this.