Question

With a single server setup, I receive events from the driver.

mongoose.connect('mongodb://localhost/mydb');
mongoose.connection.on('disconnected', function() {...});
mongoose.connection.on('error', function(err) {...});

When using a replica set (mongoose.connect('mongodb://localhost:27017/mydb,mongodb://localhost:27018/mydb');), shutting down all connected set members doesn't trigger those same events.

I'm not very familiar with the internals of the native driver and I'm wondering if this is a bug or if I need to manually detect this condition.

I'm using Mongoose 3.6.17 (mongodb driver 1.3.18)

Sans mongoose, I tried this with the same results (no events from a replica set).

require('mongodb').MongoClient.connect("mongodb://localhost:27017,localhost:27018/mydb", function(err, db) {
    if (db) {
        db.on('disconnected', function() {
            console.log('disconnected');
        }).on('error', function(err) {
            console.log('error');
        });
    }            
});
Was it helpful?

Solution

I've been having similar problems with Mongoose, asked on SO also. More recently, I've found this issue on Mongoose GitHub repository which led to this issue on the driver repository.

The Mongo driver wasn't emitting any of these events more than once, and today this has been fixed for single connections on v1.3.19.
It seems that it's a "won't fix" for now.

OTHER TIPS

I ended up doing the following:

  1. I set auto_reconnect=true
  2. Until the application has connected to the database for the first time, i disconnect and reconnect. if i don't disconnect and reconnect, any queued queries won't run. after a connection has been established at least once, those queued queries do complete and then...

for single connections: 1. forked mongoose (to use mongodb to 1.3.19) so errors get triggered more than once. 2. catch the connection error and make the app aware of the disconnection, retrying until i give up and panic or the app is reconnected. how that's done is by pinging the server every x milliseconds with a command that will not queue:

var autoReconnect = mongoose.connection.db.serverConfig.isAutoReconnect;
mongoose.connection.db.serverConfig.isAutoReconnect = function(){return false;};
mongoose.connection.db.executeDbCommand({ping:1}, {failFast: true}, function(err) {
    if (!err) {
        // we've reconnected.
    }
});
mongoose.connection.db.serverConfig.isAutoReconnect = autoReconnect;

for a replica set, i ended up polling the mongoose connection with the above ping every x milliseconds until i detect an error, in which case i set my local app state to disconnected and enter the reconnect poll loop above (2.).

here's a gist with the relevant bits. https://gist.github.com/jsas/6299412

This is a nasty inconsistency/oversight in mongoose.

Especially when developing a microservice where you're using a single server setup for development and replica set in production.

This is the way I ended up accurately tracking the status of my mongoose connection.

let alive = false;

function updateAlive() {
  return mongoose.connection
    && mongoose.connection.readyState === mongoose.STATES.connected
    // This is necessary because mongoose treats a dead replica set as still "connected".
    && mongoose.connection.db.topology.connections().length > 0;
}

mongoose.connection.on('connected', () => {
  updateAlive();
  // I think '.topology' is available on even single server connections.
  // The events just won't be emitted.
  mongoose.connection.db.topology.on('joined', () => updateAlive());
  mongoose.connection.db.topology.on('left', () => updateAlive());
});

mongoose.connection.on('disconnected', () => {
  updateAlive();
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top