3

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');
        });
    }            
});
MoatMonster
  • 267
  • 1
  • 2
  • 7

3 Answers3

2

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.

Community
  • 1
  • 1
gustavohenke
  • 40,997
  • 14
  • 121
  • 129
  • 1
    Thanks for the reply. I did attempt to mitigate the single event problem by forcibly disconnecting and reconnecting. That seemed to be working, except my clients are now getting "Connection was destroyed by application" errors (which makes sense). So the fix for 1.3.19 is good news, at least for single connections. – MoatMonster Aug 21 '13 at 18:09
  • I think I messed up by answering my own question. I should have edited the original question, I think. – MoatMonster Aug 23 '13 at 03:30
0

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

MoatMonster
  • 267
  • 1
  • 2
  • 7
0

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();
});
jshbrntt
  • 5,134
  • 6
  • 31
  • 60