Mongoose: Manera de manejar el error mongoose.connect () en el controlador de captura de promesa

Creado en 10 may. 2016  ·  31Comentarios  ·  Fuente: Automattic/mongoose

¿Cómo manejar el error mongoose.connect() en el controlador de captura? Quiero usar la cadena de inicialización de la aplicación, pero no puedo hacerlo porque mongoose.connect() no devuelve la promesa rechazada. Devuelve la promesa rechazada solo si especifico devolución de llamada, pero no es una solución perfecta.

Ejemplo:

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

Solución alterna:

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

Creo que mongoose.connect() arroja un error asíncrono en lugar de devolver una promesa rechazada para no romper la compatibilidad con versiones anteriores. Los usuarios esperan que la aplicación finalice con un código de error si algo salió mal con el establecimiento de la conexión de mangosta. Si mongoose.connect() devuelve la aplicación de promesa rechazada se terminará con el código 0 y no se enviará nada a la consola. Así que será bueno tener alguna forma de decir mongoose.connect() para devolver la promesa. Tal vez algo como 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

Comentario más útil

Solo para confirmar para cualquiera que venga más tarde, esto funciona como se esperaba:

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

Todos 31 comentarios

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 ¿Qué quisiste decir? :smiley: no quiero usar devolución de llamada)

@Jokero, lo siento, amigo

Utilice la devolución de llamada de mongoose.connect para detectar cualquier error durante la conexión.
Puede iniciar su servidor en el evento abierto.

        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 Lo sé, puedo usar la devolución de llamada para el manejo de errores, pero el problema se trata de promesas :smiley:

No use la promesa de mongoose.connect, inicie su servidor cuando la conexión esté abierta por primera vez (.once('open'))

¿Por qué? No hay diferencia en absoluto. Cuando se abre la conexión, se llamará a la devolución mongoose.connect llamada open . Para que puedas usar lo que quieras

Sí, pero como dijiste, mongoose.connect necesita una devolución de llamada en caso de error.

Por eso creé este problema :smiley:

Tengo el mismo problema.

Me gustaría poder usar mongoose.connect(...).catch(failCallback) pero cuando ocurre un error en el intento de conexión inicial, failCallback no se ejecuta. Hay algo mal con el MongooseThenable seudo-promesa de que mongoose.connect devoluciones. Además, he configurado mongoose.Promise = require('bluebird') y realmente espero que tales llamadas asincrónicas devuelvan una promesa _real_, una Bluebird en mi caso.

Sin embargo, el problema con mi failCallback no se ejecuta ocurre solo inicialmente, es decir:

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

Pero de hecho funciona así (lo cual no tiene sentido):

// 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

¿Porqué es eso?

Re: devolver una promesa real, es así por compatibilidad con versiones anteriores. Desafortunadamente, las personas confían en el comportamiento de encadenamiento de .connect() por alguna razón (#3847, #3790, etc.), por lo que lo mantendremos así por ahora :) Se agregó una solución para que .catch() pueda captar la conexión inicial asuntos.

¡Funciona! Pero, ¿estos cambios romperán algo para aquellos que esperan que el proceso de solicitud finalice cuando ocurra un error de conexión y no haya controladores de devolución de llamada y promesa?

Ejemplo:

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

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

Antes de estos cambios

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

Con estos cambios el proceso finaliza con código 0

Gracias por la sugerencia, investigaré.

¡Frio! Gracias :+1:

+1
Me encantaría poder devolver el resultado de .connect() como una Promesa completa en el encadenamiento de inicialización.

@CodeJjang, ¿esto no funciona ya? Esta funcionalidad ya ha sido lanzada

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

esto no me funciona :(
Muestra
(node:22564) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: failed to connect to server [127.0.0.1:27017] on first connect

Hmm, intenta deshacerte de la devolución de llamada en mongoose.connect()

Acabo de tener:

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

no usar promesas en mongoose 4.7.6 (más reciente en este momento), ¿alguna forma de evitar esa Advertencia?
Lo estoy usando con ExpressJS y si uso catch, arruina mi lógica y se comporta de manera extraña ya que express-session está creando un MongoStore... simplemente desordenado.

ejemplo de código por favor

Tengo el mismo problema que @matheo. Acabo de abrir este ticket:

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

Solo para confirmar para cualquiera que venga más tarde, esto funciona como se esperaba:

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

Solo para confirmar para cualquiera que venga más tarde, esto funciona como se esperaba:

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

¡También estoy usando este enfoque! Pero cuando detengo mongodb y luego ejecuto este código, no funciona.

// 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é quiere decir con 'no funciona'? ¿Hay algunos mensajes de error?

@ vkarpov15 Quiero decir que no se imprimirá ningún error

Procedimiento:

  • Paso 1: detuve el servicio mongodb
  • Paso 2: Conéctese con mongodb. En este paso, no se imprimirá ningún error en la consola, no se alcanzará el bloque catch .
    // Never reach to here
    console.log(err);
    process.exit(1);

@ nvtuan305 si se connectTimeoutMS . ¿No es ese tu caso? Si es así, ¿qué versión de MongoDB y mongoose?

@vkarpov15

mangosta informará un error después de connectTimeoutMS

En mi caso, la mangosta no informa el error después de connectTimeoutMS en el bloque catch . Estoy usando Mongodb 3.6.5 y 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 solo para confirmar, ¿se está conectando a una instancia mongodb independiente o un conjunto de réplicas?

@ vkarpov15 Estoy usando una instancia independiente.

@ nvtuan305 ¿qué sistema operativo? Además, ¿por qué espera que Mongoose no se conecte a la instancia independiente? ¿Está caída la instancia de mongod , no hay conexión de red, algo más?

El siguiente script funciona como se esperaba:

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

Producción

$ 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

Oye, parece básico, pero por favor revisa estas instrucciones.

  • Configure su dirección IP en el clúster de Mongo, incluso puede configurar el acceso desde cualquier lugar
  • Asegúrese de manejar los errores, con catch por ejemplo

lo soluciono haciendo eso

¿Fue útil esta página
0 / 5 - 0 calificaciones