Mongoose: promise catchハンドラーでmongoose.connect()エラーを処理する方法

作成日 2016年05月10日  ·  31コメント  ·  ソース: Automattic/mongoose

キャッチハンドラーでmongoose.connect()エラーを処理するにmongoose.connect()が拒否されたpromiseを返さないため、使用できません。 コールバックを指定した場合にのみ拒否されたpromiseが返されますが、完全な解決策ではありません。

例:

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()は、下位互換性を壊さないために、拒否されたpromiseを返す代わりに非同期エラーをスローすると思います。 ユーザーは、マングース接続の確立で問題が発生した場合、アプリケーションがエラーコードで終了することを期待しています。 mongoose.connect()が拒否された場合、promiseアプリケーションは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のコールバックを使用します。
イベントが開いたときにサーバーを起動できます。

        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からのpromiseを使用せず、接続が初めて開いたときにサーバーを起動します(.once( 'open'))

どうして? まったく違いはありません。 接続が開かれると、 mongoose.connectコールバックが呼び出され、返されたpromiseが実行され、 openイベントが発行されます。 だからあなたはあなたが望むものを使うことができます

はい、しかしあなたが言ったように、mongoose.connectはエラーの場合にコールバックを必要とします。

だから私はこの問題を作成しました:smiley:

同じ問題があります。

mongoose.connect(...).catch(failCallback)を使用できるようにしたいのですが、最初の接続試行時にエラーが発生すると、 failCallbackが実行されません。 mongoose.connectが返されるというMongooseThenable疑似約束に何か問題があります。 さらに、私は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:本当の約束を返す、それは下位互換性のためのその方法です。 残念ながら、人々は何らかの理由(#3847​​、#3790など)で.connect()チェーン動作に依存しているため、今のところこの方法を維持しています:) .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()の結果を、初期化チェーンの本格的なPromiseとして返すことができるようにしたいと考えています。

@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(現在最新)でpromiseを使用していない場合、その警告を回避する方法はありますか?
ExpressJSで使用していますが、catchを使用すると、ロジックがねじ込まれ、 express-sessionがMongoStoreも作成しているため、奇妙な動作をします...ただ面倒です。

コードサンプルをお願いします

@matheoと同じ問題があります。 このチケットを開いたところ:

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初期接続がmongooseはconnectTimeoutMS後にエラーを報告します。 そうではありませんか? もしそうなら、MongoDBとmongooseのどのバージョンですか?

@ vkarpov15

マングースはconnectTimeoutMS後にエラーを報告します

私の場合、mongooseはcatchブロックのconnectTimeoutMS後にエラーを報告しません。 私はMongodb3.6.5とmongoose5.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

ねえ、それは基本的なようですが、これらの指示を再確認してください

  • MongoクラスターにIPアドレスを設定すると、どこからでもアクセスを設定できます
  • 必ずcatchなどのエラーを処理してください

私はそれをやって解決します

このページは役に立ちましたか?
0 / 5 - 0 評価