Confiablemente reconectarse a MongoDB

ACTUALIZACIÓN: Estoy usando la versión 2.1 en el controlador, contra 3.2

Tengo una aplicación de nodo que utiliza MongoDB. El problema que tengo es que si el servidor MongoDB se desactiva por alguna razón, la aplicación no se vuelve a conectar. Para hacerlo bien, basé mis pruebas en el código de este tutorial oficial .

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) }); 

La idea es ejecutar este script, y luego detener mongod, y luego reiniciarlo. Así que, aquí vamos:

PRUEBA 1: detener mongod durante 10 segundos

Al detener MongoDb durante 10 segundos se obtiene el resultado deseado: dejará de ejecutar las consultas durante esos 10 segundos y luego se ejecutarán todas una vez que el servidor vuelva a ip

PRUEBA 2: detener mongod durante 30 segundos

Después de exactamente 30 segundos, empiezo a recibir:

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

El problema es que a partir de esto, cuando reinicio mongod, la conexión no se vuelve a establecer .

Soluciones?

¿Este problema tiene solución? Si es así, ¿sabes lo que es? Una vez que mi aplicación comienza a vomitar “la topología fue destruida”, la única manera de hacer que todo vuelva a funcionar es reiniciando toda la aplicación …

Hay 2 opciones de conexión que controlan cómo el controlador mongo nodejs se vuelve a conectar después de que la conexión falla

  • reconnectTries: intenta reconectar #times (predeterminado 30 veces)
  • reconnectInterval: el servidor esperará # milisegundos entre los rebashs (1000 ms predeterminados)

referencia en mongo drivers docs

Lo que significa que mongo seguirá intentando conectarse 30 veces de forma predeterminada y esperará 1 segundo antes de cada rebash. Es por eso que empiezas a ver errores después de 30 segundos.

Debe ajustar estos 2 parámetros según sus necesidades, como este ejemplo.

 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) }); 

Esto intentará 60 veces en lugar de los 30 predeterminados, lo que significa que comenzará a ver errores después de 60 segundos cuando deje de intentar volver a conectarse.

Nota: si desea evitar que la aplicación / solicitud espere hasta el vencimiento del período de reconexión, debe pasar la opción bufferMaxEntries: 0 . El precio para esto es que las solicitudes también se abortan durante interrupciones cortas de la red.

Por defecto, el controlador Mongo intentará volver a conectarse 30 veces, una por segundo. Después de eso no volverá a intentar volver a conectarse.

Puede establecer el número de rebashs en Number.MAX_VALUE para mantenerlo reconectando “casi para siempre”:

  var connection = "mongodb://127.0.0.1:27017/db"; MongoClient.connect(connection, { server : { reconnectTries : Number.MAX_VALUE, autoReconnect : true } }, function (err, db) { }); 

Está sucediendo porque podría haber cruzado el límite de conexión de rebash. Después del número de rebashs, destruye la conexión TCP y queda inactivo. Por lo tanto, aumente el número de rebashs y sería mejor si boosta la brecha entre los rebashs de conexión.

Utilice las siguientes opciones:

 retryMiliSeconds {Number, default:5000}, number of milliseconds between retries. numberOfRetries {Number, default:5}, number of retries off connection. 

Para obtener más información, consulte este enlace https://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html

Solución:

 MongoClient.connect("mongodb://localhost:27017/integration_test_?", { db: { native_parser: false, retryMiliSeconds: 100000, numberOfRetries: 100 }, server: { socketOptions: { connectTimeoutMS: 500 } } }, callback) 

El comportamiento puede diferir con las diferentes versiones del controlador. Debe mencionar su versión de controlador.

versión del controlador: 2.2.10 (más reciente) versión de db mongo: 3.0.7

El código siguiente extenderá el tiempo que mongod puede tardar en volver a subir.

 var MongoClient = require('mongodb').MongoClient , f = require('util').format; function connectCallback(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) } var options = { server: { reconnectTries: 2000,reconnectInterval: 1000 }} MongoClient.connect('mongodb://localhost:27017/test',options,connectCallback); 

El segundo argumento puede usarse para pasar las opciones del servidor.

package.json: "mongodb": "3.1.3"

Vuelva a conectar las conexiones existentes

Para ajustar la configuración de reconexión para las conexiones preestablecidas, puede modificar las opciones de reconnectTries / reconnectInterval ( valores predeterminados y documentación adicional aquí ).

Vuelva a conectar la conexión inicial

Para la conexión inicial, el cliente mongo no se vuelve a conectar si encuentra un error (ver más abajo). Creo que debería , pero mientras tanto, he creado la siguiente solución utilizando la biblioteca promise-retry (que utiliza una estrategia de retroceso exponencial).

 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 } 

Error de conexión inicial de Mongo: failed to connect to server [db:27017] on first connect