Mongoose: Способ обработки ошибки mongoose.connect() в обработчике обещаний

Созданный на 10 мая 2016  ·  31Комментарии  ·  Источник: Automattic/mongoose

Как обработать ошибку mongoose.connect() в обработчике catch? Я хочу использовать цепочку инициализации приложения, но не могу этого сделать, потому что mongoose.connect() не возвращает отклоненное обещание. Он возвращает отклоненное обещание, только если я указываю обратный вызов, но это не идеальное решение.

Пример:

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

Обходной путь:

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

Я думаю, что mongoose.connect() выдает асинхронную ошибку вместо возврата отклоненного обещания, чтобы не нарушать обратную совместимость. Пользователи ожидают, что приложение будет завершено с кодом ошибки, если что-то пойдет не так с установлением соединения мангуста. Если mongoose.connect() вернет отклоненное обещание, приложение будет завершено с кодом 0, и ничего не будет выведено на консоль. Поэтому было бы неплохо иметь какой-то способ сказать mongoose.connect() чтобы вернуть обещание. Может быть что-то вроде 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

Самый полезный комментарий

Просто чтобы подтвердить для тех, кто придет позже, это работает, как и ожидалось:

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

Все 31 Комментарий

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 Что ты имел в виду? :smiley: Я не хочу использовать обратный вызов)

@Jokero, извини, чувак......... неправильно понял твой вопрос. :)

Используйте обратный вызов mongoose.connect, чтобы поймать любую ошибку во время соединения.
Вы можете запустить свой сервер в событии open.

        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 Я знаю, я могу использовать обратный вызов для обработки ошибок, но проблема в обещаниях :smiley:

Не используйте обещание от mongoose.connect, запустите свой сервер, когда соединение открыто в первый раз (.once('open'))

Почему? Никакой разницы. Когда соединение открыто, будет вызван обратный вызов mongoose.connect , а также будет выполнено возвращенное обещание и будет сгенерировано событие open . Таким образом, вы можете использовать то, что хотите

Да, но, как вы сказали, mongoose.connect нуждается в обратном вызове в случае ошибки.

Поэтому я и создал эту тему :smiley:

У меня такая же проблема.

Я хотел бы иметь возможность использовать mongoose.connect(...).catch(failCallback) но когда возникает ошибка при первоначальной попытке подключения, failCallback не выполняется. Там что - то не так с MongooseThenable псевдо-обещание , что mongoose.connect возвратов. Более того, я настроил mongoose.Promise = require('bluebird') и действительно ожидаю, что такие асинхронные вызовы будут возвращать _real_ promise, в моем случае Bluebird.

Однако проблема с тем, что мой failCallback не выполняется, возникает только изначально, то есть:

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

Но на самом деле это работает так (что бессмысленно):

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

Это почему?

Re: возврат реального обещания, это так для обратной совместимости. К сожалению, люди по какой-то причине полагаются на цепное поведение .connect() (#3847, #3790 и т. д.), поэтому мы пока оставляем его таким :) Добавлено исправление, позволяющее .catch() перехватывать начальное соединение. вопросы.

Оно работает! Но не сломают ли эти изменения что-то для тех, кто ожидает, что процесс приложения завершится, когда произойдет ошибка соединения и нет обработчиков обратного вызова и промиса?

Пример:

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

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

До этих изменений

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

С этими изменениями процесс завершается кодом 0

Спасибо за предложение, будем разбираться.

Прохладный! Спасибо :+1:

+1
Хотелось бы иметь возможность вернуть результат .connect() в виде полноценного промиса в цепочке инициализации.

@CodeJjang это уже не работает? Эта функция уже выпущена

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

Это не работает для меня :(
Это шоу
(node:22564) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: failed to connect to server [127.0.0.1:27017] on first connect

Хм, попробуйте избавиться от обратного вызова в mongoose.connect()

Я только что получил:

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

не используя обещания на мангусте 4.7.6 (последняя прямо сейчас), есть ли способ избежать этого предупреждения?
Я использую его с ExpressJS, и если я использую catch, он портит мою логику и ведет себя странно, поскольку express-session тоже создает MongoStore... просто беспорядочно.

Пример кода пожалуйста

У меня та же проблема, что и у @mateo. Только что открыл этот тикет:

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

Просто чтобы подтвердить для тех, кто придет позже, это работает, как и ожидалось:

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

Просто чтобы подтвердить для тех, кто придет позже, это работает, как и ожидалось:

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

Я тоже использую этот метод! Но когда я останавливаю mongodb, а затем запускаю этот код, он не работает.

// 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 что вы подразумеваете под «не работает»? Есть сообщения об ошибках?

@ vkarpov15 Я имею в виду, что ошибка не будет напечатана

Процедура:

  • Шаг 1: я остановил службу mongodb
  • Шаг 2: Подключитесь к mongodb. На этом шаге в консоль не будет выведена ошибка, блок catch не будет достигнут.
    // Never reach to here
    console.log(err);
    process.exit(1);

@ nvtuan305 nvtuan305, если время ожидания исходного соединения истекло, мангуст сообщит об ошибке после connectTimeoutMS . Разве это не так для вас? Если да, то какая версия MongoDB и мангуста?

@vkarpov15

мангуст сообщит об ошибке после connectTimeoutMS

В моем случае мангуст не сообщает об ошибке после connectTimeoutMS в блоке catch . Я использую MongoDB 3.6.5 и мангуст 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 просто для подтверждения, вы подключаетесь к автономному экземпляру mongodb или к набору реплик?

@ vkarpov15 Я использую автономный экземпляр.

@ nvtuan305 какая операционная система? Кроме того, почему вы ожидаете, что Mongoose не сможет подключиться к автономному серверу - не работает ли экземпляр mongod , нет ли сетевого подключения, что-то еще?

Ниже скрипт работает как положено:

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

Вывод

$ 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

Эй, это кажется простым, но, пожалуйста, перепроверьте эти инструкции

  • Установите свой IP-адрес в кластере Mongo, вы даже можете установить доступ отовсюду
  • Обязательно обрабатывайте ошибки, например, с помощью catch

Я решаю это, делая это

Была ли эта страница полезной?
0 / 5 - 0 рейтинги