How to ensure Node.js keeps running after MonogDB

2020-02-26 13:30发布

问题:

I have an error-handling middlware in Express that tries to catch all incoming errors:

app.use(function(err, req, res, next){
  console.error(err.stack);
  res.status(500);
  res.render('500.jade');
});

But for some reason whenever I close mongod process, my application crashes with the following stack trace:

Error: failed to connect to [localhost:27017]
    at null.<anonymous> (/<hidden>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:540:74)
    at EventEmitter.emit (events.js:106:17)
    at null.<anonymous> (/<hidden>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:140:15)
    at EventEmitter.emit (events.js:98:17)
    at Socket.<anonymous> (/<hidden>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:478:10)
    at Socket.EventEmitter.emit (events.js:95:17)
    at net.js:441:14
    at process._tickCallback (node.js:415:13)

Process finished with exit code 8

I have tried using the following configuration, but it didn't help me:

var options = {
  server:{
    auto_reconnect: true,
      poolSize: 10,
      socketOptions:{
      keepAlive: 1
    }
  },
  db: {
    numberOfRetries: 10,
    retryMiliSeconds: 1000
  }
}

mongoose.connect(config.db, options);

One might wonder "why would you want your application to be running if it's essentially no longer functioning without a database connection?". I don't want it to crash and restart itself. Supervisor and Forever modules seem to stop trying to reconnect after a certain number of tries, thus leaving your application hanging in a crashed state.

Ideally, when MongoDB crashes I would like to display a 500.jade error page to users, meanwhile server should keep trying to reconnect to the database every 10 seconds. Once reconnected, resume all normal operations.

EDIT: None of the solutions posted below have worked for me, with the exception of domains.

回答1:

Try initializing the DB in a domain, that would catch the errors without crashing

var d = require('domain').create();

d.on('error', function(er) {
    console.log('Oh no, something wrong with DB');
});

d.run(function() {
    mongoose.connect(config.db, options);
});

It's generally a good idea to let the server restart when something crashes, but as you're already aware of this and want to avoid it, wrapping whatever fails in domains is the way to do it.



回答2:

This is what I do to deal with Mongo failing - add it as middleware. It will also try to reconnect again.

// Handler in case Mongo  goes down
app.use(function(req, res, next) {
  // We lost connection!
  if (1 !== mongoose.connection.readyState) {

    // Reconnect if we can
    mongoose.connect(config.db, options);
    res.status(503);
    throw new Error('Mongo not available');
  }
  next();

});

This assume you have a standard 50x error handler somewhere that will show a nice page to the user.

The reconnect is there for the next user/page load to check if it's back up. Works nice.



回答3:

The MongoDB driver issues a "close" event when the connection is lost. You can tap on this event and flag the DB as unavailable and write any logic based on that.

db.on('close', function() {
  // handle the disconnect
  dbAvailable = false;
});

I've got a small NPM module that handles this if you are interested: https://npmjs.org/package/mongoconnect