Mongoose: Manière de gérer l'erreur mongoose.connect() dans le gestionnaire de capture de promesse

Créé le 10 mai 2016  ·  31Commentaires  ·  Source: Automattic/mongoose

Comment gérer l'erreur mongoose.connect() dans le gestionnaire de capture ? Je souhaite utiliser la chaîne d'initialisation de l'application mais je ne peux pas le faire car mongoose.connect() ne renvoie pas la promesse rejetée. Il ne renvoie la promesse rejetée que si je spécifie le rappel, mais ce n'est pas une solution parfaite.

Exemple:

mongoose.connect('mongodb://127.0.0.2/test') // if error it will throw async error
    .then(() => { // if all is ok we will be here
        return server.start();
    })
    .catch(err => { // we will not be here...
        console.error('App starting error:', err.stack);
        process.exit(1);
    });

Solution de contournement:

mongoose.connect('mongodb://127.0.0.2/test', function() { /* dummy function */ })
    .then(() => {
        return server.start();
    })
    .catch(err => { // mongoose connection error will be handled here
        console.error('App starting error:', err.stack);
        process.exit(1);
    });

Je pense que mongoose.connect() génère une erreur asynchrone au lieu de renvoyer une promesse rejetée afin de ne pas rompre la compatibilité descendante. Les utilisateurs s'attendent à ce que l'application se termine avec un code d'erreur si quelque chose ne va pas avec l'établissement de la connexion Mangoose. Si mongoose.connect() renvoie la demande de promesse rejetée se terminera avec le code 0 et rien ne sera sorti sur la console. Il sera donc bon d'avoir un moyen de dire mongoose.connect() pour retourner la promesse. Peut-être quelque chose comme exec() :

mongoose.connect('mongodb://127.0.0.2/test').exec()
    .then(() => { // if all is ok we will be here
        return server.start();
    })
    .catch(err => { // if error we will be here
        console.error('App starting error:', err.stack);
        process.exit(1);
    });
can't reproduce

Commentaire le plus utile

Juste pour confirmer pour ceux qui viendront plus tard, cela fonctionne comme prévu :

mongoose.connect('http://127.0.0.1:27017/test')
  .then(() => {
    server.start();
  })
  .catch((err) => {
    console.log('Error on start: ' + err.stack);
    process.exit(1);
  });

Tous les 31 commentaires

mongoose.connect('mongodb://localhost/dbCollection', function(err, db) {
    if (err) {
        console.log('Unable to connect to the server. Please start the server. Error:', err);
    } else {
        console.log('Connected to Server successfully!');
    }
});

@ nasr18 Que

@Jokero désolé mec.......

Utilisez le rappel de mongoose.connect pour détecter toute erreur lors de la connexion.
Vous pouvez démarrer votre serveur en cas d'ouverture.

        mongoose.connection.once('open', function() {
            logger.info('MongoDB event open');
            logger.debug('MongoDB connected [%s]', url);

            mongoose.connection.on('connected', function() {
                logger.info('MongoDB event connected');
            });

            mongoose.connection.on('disconnected', function() {
                logger.warn('MongoDB event disconnected');
            });

            mongoose.connection.on('reconnected', function() {
                logger.info('MongoDB event reconnected');
            });

            mongoose.connection.on('error', function(err) {
                logger.error('MongoDB event error: ' + err);
            });

            // return resolve();
            return server.start();
        });

        return mongoose.connect(url, options, function(err) {
            if (err) {
                logger.error('MongoDB connection error: ' + err);
                // return reject(err);
                process.exit(1);
            }
        });

@mathieug je sais, je peux utiliser le rappel pour la gestion des erreurs mais le problème concerne les promesses :smiley:

N'utilisez pas la promesse de mongoose.connect, démarrez votre serveur lorsque la connexion est ouverte pour la première fois (.once('open'))

Pourquoi? Aucune différence du tout. Lorsque la connexion est ouverte, le rappel mongoose.connect sera appelé ainsi que la promesse retournée sera remplie et l'événement open sera émis. Donc tu peux utiliser ce que tu veux

Oui mais comme vous l'avez dit, mongoose.connect a besoin d'un rappel en cas d'erreur.

C'est pourquoi j'ai créé ce problème :smiley:

J'ai le même problème.

J'aimerais pouvoir utiliser mongoose.connect(...).catch(failCallback) mais lorsqu'une erreur se produit lors de la tentative de connexion initiale, failCallback ne s'exécute pas. Il y a quelque chose de mal avec le MongooseThenable pseudo-promesse mongoose.connect retours. De plus, j'ai configuré mongoose.Promise = require('bluebird') et je m'attends vraiment à ce que de tels appels asynchrones renvoient une _réelle_ promesse, une Bluebird dans mon cas.

Le problème avec mon failCallback ne s'exécute pas, cependant, ne se produit qu'au début, c'est-à-dire :

// First kill mongod instance so that Mongoose cannot connect and start the app
mongoose.connect(uri, options).catch(failCallback); // failCallback does _not_ get called
// Then stop the app, start mongod instance so that Mongoose can connect, start the app
mongoose.connect(uri, options).then(successCallback); // successCallback gets called
// Then kill mongod instance so that Mongoose disconnects (while the app is running)
mongoose.connection.on('disconnected', function () {
  setTimeout(function () {
    mongoose.connect(uri, options).catch(reconnectFailCallback); // now reconnectFailCallback _does_ get called
  }, randomDelayOfAboutASecond);
});

Mais effectivement ça marche comme ça (ce qui n'a pas de sens) :

// First kill mongod instance so that Mongoose cannot connect and start the app
var dummyNoopCallback = function () {};
mongoose.connect(uri, options, dummyNoopCallback).catch(failCallback); // failCallback _does_ get called

Pourquoi donc?

Re : retourner une vraie promesse, c'est comme ça pour la rétrocompatibilité. Malheureusement, les gens s'appuient sur le comportement de chaînage de .connect() pour une raison quelconque (#3847, #3790, etc.), nous le gardons donc pour l'instant :) Ajout d'un correctif afin que .catch() puisse attraper la connexion initiale problèmes.

Ça marche! Mais ces changements casseront-ils quelque chose pour ceux qui s'attendent à ce que le processus de candidature soit terminé lorsqu'une erreur de connexion se produit et qu'il n'y a pas de gestionnaires de rappel et de promesse ?

Exemple:

const mongoose = require('mongoose');
mongoose.Promise = Promise;

mongoose.connect('mongodb://127.0.0.2/test'); // no callback and promise handlers

Avant ces changements

/home/dmitry/example/node_modules/mongodb/lib/server.js:242
        process.nextTick(function() { throw err; })
                                      ^
Error: connect ECONNREFUSED 127.0.0.2:27017
    at Object.exports._errnoException (util.js:870:11)
    at exports._exceptionWithHostPort (util.js:893:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1057:14)

Avec ces changements, le processus est terminé avec 0 code

Merci pour la suggestion, va étudier.

Cool! Merci :+1:

+1
J'adorerais pouvoir retourner le résultat de .connect() en tant que promesse à part entière dans le chaînage d'initialisation.

@CodeJjang ça ne marche pas déjà ? Cette fonctionnalité a déjà été publiée

mongoose.connect('mongodb://127.0.0.2/test', function() { /* dummy function */ })
    .then(() => {
        return server.start();
    })
    .catch(err => { // mongoose connection error will be handled here
        console.error('App starting error:', err.stack);
        process.exit(1);
    });

Cela ne fonctionne pas pour moi :(
Cela montre
(node:22564) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: failed to connect to server [127.0.0.1:27017] on first connect

Hmm, essayez de vous débarrasser du rappel dans mongoose.connect()

Je viens de recevoir:

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1):
MongoError: failed to connect to server [localhost:17551] on first connect

ne pas utiliser les promesses sur la mangouste 4.7.6 (la plus récente en ce moment), un moyen d'éviter cet avertissement ?
Je l'utilise avec ExpressJS et si j'utilise catch, il bousille ma logique et se comporte bizarrement car express-session crée aussi un MongoStore... tout simplement désordonné.

Exemple de code s'il vous plaît

J'ai le même problème que @matheo. Je viens d'ouvrir ce ticket :

https://github.com/christkv/mongodb-core/issues/163

Juste pour confirmer pour ceux qui viendront plus tard, cela fonctionne comme prévu :

mongoose.connect('http://127.0.0.1:27017/test')
  .then(() => {
    server.start();
  })
  .catch((err) => {
    console.log('Error on start: ' + err.stack);
    process.exit(1);
  });

Juste pour confirmer pour ceux qui viendront plus tard, cela fonctionne comme prévu :

mongoose.connect('http://127.0.0.1:27017/test')
  .then(() => {
    server.start();
  })
  .catch((err) => {
    console.log('Error on start: ' + err.stack);
    process.exit(1);
  });

J'utilise aussi cette approche ! Mais lorsque j'arrête mongodb puis que j'exécute ce code, cela ne fonctionne pas.

// mongoose version 5.4.14
mongoose
  .connect(databaseUri, {
    promiseLibrary: bluebird,
    useNewUrlParser: true,
    useFindAndModify: false,
    useCreateIndex: true,
    // Automatically try to reconnect when it loses connection to MongoDB
    autoReconnect: true,
    // Never stop trying to reconnect
    reconnectTries: Number.MAX_VALUE,
    // Reconnect every 500ms
    reconnectInterval: 500,
    // Maintain up to 10 socket connections. If not connected,
    // return errors immediately rather than waiting for reconnect
    poolSize: 10,
    // Give up initial connection after 10 seconds
    connectTimeoutMS: 10000,
  })
  .catch((err) => {
    console.log(err);
    process.exit(1);
  });

@ nvtuan305 qu'entendez-vous par « ne fonctionne pas » ? Y a-t-il des messages d'erreur ?

@ vkarpov15 Je veux dire qu'aucune erreur ne sera imprimée

Procédure:

  • Étape 1 : j'ai arrêté le service mongodb
  • Étape 2 : Connectez-vous avec mongodb. A cette étape, aucune erreur ne sera imprimée dans la console, le bloc catch ne sera pas atteint.
    // Never reach to here
    console.log(err);
    process.exit(1);

@nvtuan305 si la connexion initiale connectTimeoutMS . Ce n'est pas le cas pour toi ? Si oui, quelle version de MongoDB et mongoose ?

@vkarpov15

mangouste signalera une erreur après connectTimeoutMS

Dans mon cas, la mangouste ne signale pas d'erreur après connectTimeoutMS au bloc catch . J'utilise Mongodb 3.6.5 et mongoose 5.4.14

> mongod --version
db version v3.6.5
git version: a20ecd3e3a174162052ff99913bc2ca9a839d618
OpenSSL version: OpenSSL 1.0.2p  14 Aug 2018
allocator: system
modules: none
build environment:
    distarch: x86_64
    target_arch: x86_64

@ nvtuan305 juste pour confirmer, vous connectez-vous à une instance mongodb autonome ou à un jeu de réplicas ?

@ vkarpov15 J'utilise une instance autonome.

@nvtuan305 quel système d'exploitation ? De plus, pourquoi pensez-vous que Mongoose ne parvient pas à se connecter à l'instance autonome ? L'instance mongod est-elle en panne, n'y a-t-il pas de connexion réseau, autre chose ?

Le script ci-dessous fonctionne comme prévu :

const assert = require('assert');
const mongoose = require('mongoose');
mongoose.set('debug', true);

run().then(() => console.log('done')).catch(error => console.error(error.stack));

async function run() {
  console.log(mongoose.version);

  const start = Date.now();
  const opts = { useNewUrlParser: true, connectTimeoutMS: 1000 };
  await mongoose.connect('mongodb://doesntexist.com:27017/test', opts).
    catch(error => { console.log(`Caught "${error.message}" after ${Date.now() - start}`); });
}

Sortir

$ node gh-4135.js 
5.4.14
Caught "failed to connect to server [doesntexist.com:27017] on first connect [MongoNetworkError: connection 0 to doesntexist.com:27017 timed out]" after 1024
done
$ ^C

Hé, cela semble basique mais veuillez vérifier ces instructions

  • Définissez votre adresse IP sur le cluster Mongo, vous pouvez même définir un accès depuis n'importe où
  • Veillez à gérer les erreurs, avec catch par exemple

je le résous en faisant ça

Cette page vous a été utile?
0 / 5 - 0 notes