web-dev-qa-db-fra.com

Reconnecter de manière fiable à MongoDB

UPDATE: J'utilise la version 2.1 sur le pilote, contre 3.2

J'ai une application de noeud qui utilise MongoDB. Le problème que j'ai est que si le serveur MongoDB tombe en panne pour une raison quelconque, l'application ne se reconnecte pas . Pour obtenir ce droit, j'ai basé mes tests sur le code dans ce tutoriel officiel .

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

L'idée est d'exécuter ce script, puis d'arrêter Mongod, puis de le redémarrer . Alors, c'est parti:

TEST 1: arrêt du Mongod pendant 10 secondes

Arrêter MongoDb pendant 10 secondes produit le résultat souhaité: les requêtes ne seront plus exécutées pendant ces 10 secondes, puis toutes les une fois que le serveur sera de retour ip

TEST 2: arrêter le mongod pendant 30 secondes

Après exactement 30 secondes, je commence à obtenir:

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

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

Le problème est que, à partir de ce moment, lorsque je redémarre Mongodod, la connexion n'est pas rétablie.

Solutions?

Ce problème a-t-il une solution? Si oui, savez-vous ce que c'est? Une fois que mon application a commencé à vomir "la topologie a été détruite", le seul moyen de tout remettre en marche est de redémarrer l'ensemble de l'application ...

24
Merc

Il y a 2 options de connexion qui contrôlent la façon dont le pilote mongo nodejs se reconnecte après l'échec de la connexion

  • reconnectTries: tentative de reconnexion #times (30 fois par défaut)
  • reconnectInterval: le serveur attendra # millisecondes entre les tentatives (par défaut 1000 ms)

référence sur les manuels de pilotes mongo

Ce qui signifie que mongo continuera à essayer de se connecter 30 fois par défaut et attendra 1 seconde avant chaque nouvelle tentative. C'est pourquoi vous commencez à voir des erreurs après 30 secondes.

Vous devriez modifier ces 2 paramètres en fonction de vos besoins, comme dans cet exemple.

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

Cela essaiera 60 fois au lieu de 30 par défaut, ce qui signifie que vous commencerez à voir des erreurs après 60 secondes quand il cessera d'essayer de vous reconnecter.

Remarque: si vous souhaitez empêcher l'application/la requête d'attendre jusqu'à l'expiration de la période de reconnexion, vous devez passer l'option bufferMaxEntries: 0. Le prix pour cela est que les demandes sont également abandonnées lors de brèves interruptions du réseau.

21
Gaafar

Par défaut, le pilote Mongo essaiera de se reconnecter 30 fois, une toutes les secondes. Après cela, il ne tentera plus de se reconnecter.

Vous pouvez définir le nombre de tentatives sur Number.MAX_VALUE pour qu'il reste reconnecté "presque pour toujours":

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

    });
5
Javier Ferrero

package.json: "mongodb": "3.1.3"

Reconnecter les connexions existantes

Pour affiner la configuration de la reconnexion pour les connexions pré-établies, vous pouvez modifier les options reconnectTriesreconnectInterval ( les valeurs par défaut et une documentation supplémentaire ici ).

Reconnecter la connexion initiale

Pour la connexion initiale, le client mongo ne se reconnecte pas s’il rencontre une erreur (voir ci-dessous). Je pense que cela devrait , mais dans l’intervalle, j’ai créé la solution de contournement suivante en utilisant le promise-retry (qui utilise une stratégie de sauvegarde exponentielle).

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 }

Erreur de connexion initiale _/Mongo:failed to connect to server [db:27017] on first connect

3
Nick Grealy

Cela se produit car la limite de nouvelle tentative de connexion a peut-être été dépassée. Après nombre de tentatives, il détruit la connexion TCP et devient inactif. Donc, pour cela, augmentez le nombre de tentatives et il serait préférable d’augmenter l’écart entre les tentatives de connexion.

Utilisez les options ci-dessous:

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

Pour plus de détails, consultez ce lien https://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html

Solution:

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

Le comportement peut différer selon les versions du pilote. Vous devriez mentionner votre version de pilote. 

version du pilote: 2.2.10 (dernière) version mongo db: 3.0.7

Le code ci-dessous prolongera le temps que mongod peut prendre pour revenir. 

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

Le 2ème argument peut être utilisé pour passer les options du serveur. 

1
inaitgaJ

Avec le pilote mongodb 3.1.10, vous pouvez configurer votre connexion en tant que

MongoClient.connect(connectionUrl, {
    reconnectInterval: 10000, // wait for 10 seconds before retry
    reconnectTries: Number.MAX_VALUE, // retry forever
}, function(err, res) {
    console.log('connected') 
})

Vous n'êtes pas obligé de spécifier autoReconnect: true car c'est la valeur par défaut.

1
Rico Chen