Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reliably reconnect to MongoDB

UPDATE: I am using the 2.1 version on the driver, against 3.2

I have a node application that uses MongoDB. The problem I have is that if the MongoDB server goes down for any reason, the application doesn't reconnect. To get this right, I based my tests on the code in this official tutorial.

var MongoClient = require('mongodb').MongoClient   , f = require('util').format;  MongoClient.connect('mongodb://localhost:27017/test',   // Optional: uncomment if necessary // { db: { bufferMaxEntries: 3 } },   function(err, db) {   var col = db.collection('t');    setInterval(function() {     col.insert({a:1}, function(err, r) {       console.log("insert")       console.log(err)        col.findOne({}, function(err, doc) {         console.log("findOne")         console.log(err)       });     })   }, 1000) }); 

The idea is to run this script, and then stop mongod, and then restart it. So, here we go:

TEST 1: stopping mongod for 10 seconds

Stopping MongoDb for 10 seconds does the desired result: it will stop running the queries for those 10 seconds, and then will run all of them once the server is back ip

TEST 2: stopping mongod for 30 seconds

After exactly 30 seconds, I start getting:

{ [MongoError: topology was destroyed] name: 'MongoError', message: 'topology was destroyed' } insert  { [MongoError: topology was destroyed] name: 'MongoError', message: 'topology was destroyed' } 

The trouble is that from this on, when I restart mongod, the connection is not re-establised.

Solutions?

Does this problem have a solution? If so, do you know what it is? Once my app starts puking "topology was destroyed", the only way to get everything to work again is by restarting the whole app...

like image 365
Merc Avatar asked Sep 29 '16 16:09

Merc


People also ask

Should I keep MongoDB connection open?

It is best practice to keep the connection open between your application and the database server.

Why my database is not connecting in MongoDB?

If you have created a user and are having trouble authenticating, try the following: Check that you are using the correct username and password for your database user, and that you are connecting to the correct database deployment. Check that you are specifying the correct authSource database in your connection string.

What is Poolsize MongoDB?

Most MongoDB drivers support a parameter that sets the max number of connections (pool size) available to your application. The connection pool size can be thought of as the max number of concurrent requests that your driver can service.


2 Answers

There are 2 connection options that control how mongo nodejs driver reconnects after connection fails

  • reconnectTries: attempt to reconnect #times (default 30 times)
  • reconnectInterval: Server will wait # milliseconds between retries (default 1000 ms)

reference on mongo driver docs

Which means that mongo will keep trying to connect 30 times by default and wait 1 second before every retry. Which is why you start seeing errors after 30 seconds.

You should tweak these 2 parameters based on you needs like this sample.

var MongoClient = require('mongodb').MongoClient,     f = require('util').format;  MongoClient.connect('mongodb://localhost:27017/test',      {         // retry to connect for 60 times         reconnectTries: 60,         // wait 1 second before retrying         reconnectInterval: 1000     },      function(err, db) {         var col = db.collection('t');          setInterval(function() {             col.insert({                 a: 1             }, function(err, r) {                 console.log("insert")                 console.log(err)                  col.findOne({}, function(err, doc) {                     console.log("findOne")                     console.log(err)                 });             })         }, 1000)     }); 

This will try 60 times instead of the default 30, which means that you'll start seeing errors after 60 seconds when it stops trying to reconnect.

Sidenote: if you want to prevent the app/request from waiting until the expiration of the reconnection period you have to pass the option bufferMaxEntries: 0. The price for this is that requests are also aborted during short network interruptions.

like image 174
gafi Avatar answered Sep 23 '22 18:09

gafi


package.json: "mongodb": "3.1.3"

Reconnect existing connections

To fine-tune the reconnect configuration for pre-established connections, you can modify the reconnectTries/reconnectInterval options (default values and further documentation here).

Reconnect initial connection

For the initial connection, the mongo client does not reconnect if it encounters an error (see below). I believe it should, but in the meantime, I've created the following workaround using the promise-retry library (which uses an exponential backoff strategy).

const promiseRetry = require('promise-retry') const MongoClient = require('mongodb').MongoClient  const options = {   useNewUrlParser: true,   reconnectTries: 60,   reconnectInterval: 1000,   poolSize: 10,   bufferMaxEntries: 0 }  const promiseRetryOptions = {   retries: options.reconnectTries,   factor: 1.5,   minTimeout: options.reconnectInterval,   maxTimeout: 5000 }  const connect = (url) => {   return promiseRetry((retry, number) => {     console.log(`MongoClient connecting to ${url} - retry number: ${number}`)     return MongoClient.connect(url, options).catch(retry)   }, promiseRetryOptions) }  module.exports = { connect } 

Mongo Initial Connect Error: failed to connect to server [db:27017] on first connect

like image 43
Nick Grealy Avatar answered Sep 22 '22 18:09

Nick Grealy