Mongoose: Maneira de lidar com o erro mongoose.connect() no manipulador de captura de promessa

Criado em 10 mai. 2016  ·  31Comentários  ·  Fonte: Automattic/mongoose

Como lidar com o erro mongoose.connect() no manipulador de captura? Eu quero usar a cadeia de inicialização do aplicativo, mas não posso fazer isso porque mongoose.connect() não retorna a promessa rejeitada. Ele retorna a promessa rejeitada apenas se eu especificar o retorno de chamada, mas não é uma solução perfeita.

Exemplo:

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

Gambiarra:

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

Eu acho que mongoose.connect() lança um erro assíncrono em vez de retornar a promessa rejeitada para não quebrar a compatibilidade com versões anteriores. Os usuários esperam que o aplicativo seja finalizado com o código de erro se algo der errado com o estabelecimento da conexão do mangusto. Se mongoose.connect() retornar, o aplicativo de promessa rejeitado será finalizado com código 0 e nada será enviado para o console. Então será bom ter alguma forma de dizer mongoose.connect() para devolver a promessa. Talvez 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

Comentários muito úteis

Apenas para confirmar para quem vem mais tarde, isso funciona como esperado:

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 comentários

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 O que você quis dizer? :smiley: não quero usar callback)

@Jokero desculpe cara ......... não

Use o retorno de chamada de mongoose.connect para detectar qualquer erro durante a conexão.
Você pode iniciar seu servidor no evento aberto.

        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 Eu sei, posso usar o retorno de chamada para tratamento de erros, mas o problema é sobre promessas :smiley:

Não use a promessa de mongoose.connect, inicie seu servidor quando a conexão for aberta pela primeira vez (.once('open'))

Por quê? Nenhuma diferença. Quando a conexão for aberta, o callback mongoose.connect será chamado, assim como a promessa retornada será cumprida e o evento open será emitido. Então você pode usar o que quiser

Sim, mas como você disse, mongoose.connect precisa de um retorno de chamada em caso de erro.

Por isso criei esta edição :smiley:

Eu tenho o mesmo problema.

Eu gostaria de poder usar mongoose.connect(...).catch(failCallback) mas quando ocorre um erro na tentativa inicial de conexão failCallback não executa. Há algo errado com a pseudo-promessa MongooseThenable que mongoose.connect retorna. Além disso, configurei mongoose.Promise = require('bluebird') e realmente espero que essas chamadas assíncronas retornem uma promessa _real_, uma promessa Bluebird no meu caso.

O problema do meu failCallback não executar, porém, acontece apenas inicialmente, ou seja:

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

Mas de fato funciona assim (o que não faz 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

Por que é que?

Re: retornar uma promessa real, é assim para compatibilidade com versões anteriores. Infelizmente, as pessoas confiam no comportamento de encadeamento .connect() por algum motivo (#3847, #3790, etc), então estamos mantendo assim por enquanto :) Adicionada uma correção para que .catch() possa capturar a conexão inicial questões.

Funciona! Mas essas mudanças quebrarão algo para aqueles que esperam que o processo do aplicativo seja concluído quando ocorrer um erro de conexão e não houver manipuladores de retorno de chamada e promessa?

Exemplo:

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

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

Antes dessas mudanças

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

Com essas alterações o processo é finalizado com 0 código

Obrigado pela sugestão, vou investigar.

Legal! Obrigado :+1:

+1
Adoraria poder retornar o resultado de .connect() como uma promessa completa no encadeamento de inicialização.

@CodeJjang isso já não funciona? Esta funcionalidade já foi lançada

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

Isso não está funcionando para mim :(
Isso mostra
(node:22564) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: failed to connect to server [127.0.0.1:27017] on first connect

Hmm tente se livrar do callback em mongoose.connect()

Eu acabei de receber:

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

não usando promessas no mangusto 4.7.6 (mais recente agora), alguma maneira de evitar esse aviso?
Estou usando com ExpressJS e se eu usar catch, ele estraga minha lógica e se comporta de forma estranha, pois express-session está criando um MongoStore também... apenas confuso.

Exemplo de código por favor

Estou com o mesmo problema do @matheo. Acabei de abrir este ticket:

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

Apenas para confirmar para quem vem mais tarde, isso funciona como esperado:

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

Apenas para confirmar para quem vem mais tarde, isso funciona como esperado:

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

Estou usando essa abordagem também! Mas quando eu paro o mongodb e executo este código, não está funcionando.

// 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 o que você quer dizer com 'não está funcionando'? Existem algumas mensagens de erro?

@vkarpov15 Quero dizer que nenhum erro será impresso

Procedimento:

  • Etapa 1: parei o serviço mongodb
  • Etapa 2: Conecte-se com mongodb. Nesta etapa, nenhum erro será impresso no console, o bloco catch não será alcançado.
    // Never reach to here
    console.log(err);
    process.exit(1);

@nvtuan305 se a conexão inicial connectTimeoutMS . Não é esse o seu caso? Em caso afirmativo, qual versão do MongoDB e do mangusto?

@vkarpov15

mangusto irá relatar um erro após connectTimeoutMS

No meu caso, o mangusto não relata erro após connectTimeoutMS no bloco catch . Estou usando o Mongodb 3.6.5 e o mangusto 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 apenas para confirmar, você está se conectando a uma instância mongodb autônoma ou a um conjunto de réplicas?

@vkarpov15 Estou usando instância autônoma.

@ nvtuan305 qual sistema operacional? Além disso, por que você espera que o Mongoose não consiga se conectar ao autônomo - a instância mongod inativa, não há conexão de rede, algo mais?

O script abaixo funciona como esperado:

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

Saída

$ 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

Ei, parece básico, mas por favor, verifique essas instruções

  • Defina seu endereço IP no cluster Mongo, você pode até definir o acesso de qualquer lugar
  • Certifique-se de lidar com erros, com catch, por exemplo

eu resolvo fazendo isso

Esta página foi útil?
0 / 5 - 0 avaliações