[node.js] mongooseでクエリをタイムアウトさせるには

MongoDB

tl;dr

  • MongoDBではv2.6から cursor.maxTimeMS()によって処理をタイムアウトさせられる
  • 各ドライバから使用可能
  • mongooseでは mongoose.Query#maxTime メソッドで指定可能

サーバ側で処理をタイムアウトさせるには

MongoDBでは、v2.6からサーバ側で処理の実行タイムリミットを設定できます。
処理のタイムリミットは、cursor.maxTimeMS() メソッドを呼ぶことで設定できます。
この maxTimeMS を設定すると、指定したタイムリミットを超えて検索やアップデートが実行された場合、その処理を中止します。

以下のようにコンソールで試せます:

db.collection.find({description: /August [0-9]+, 1969/}).maxTimeMS(50)

各ドライバでのmaxTimeMSの使用方法

各ドライバといっても調べたものだけを列挙しておきます。

PHP

例:

$cursor = $collection->find();
$cursor->maxTimeMS(2000);

try {
    $results = iterator_to_array($cursor);
} catch (MongoExecutionTimeoutException $e) {
    echo "query took too long!";
}

ちなみに、PHPにはMongoCursor::timeout もあります。
このメソッドはクライアント側でタイムアウト処理を行うものです。
サーバ側では処理をキャンセルしないので、注意です。

node.js

こちらに詳しく書いてあります。
例:

var MongoClient = require('mongodb').MongoClient;

MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
    // Get an aggregation cursor
    var cursor = db.collection('data')
        .find({"$where": "sleep(1000) || true"})
        .maxTimeMS(50);

    // Get alll the items
    cursor.toArray(function(err, items) {
        console.dir(err);
        console.dir(items);
        db.close();
    });
});

mongooseでタイムアウトさせるには

MongoDBのnode.jsにおけるODM(Object Data Mapping)のmongooseでもmaxTimeMSに対応しています。
v3.8.13 から利用できるようになりました。
該当の変更は こちら
実際には子分モジュールの mquery で実装されています。

使い方はシンプル:

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var Cat = mongoose.model('Cat', { name: String });
Cat.find({name: 'Zildjian' }).maxTime(1000).exec(function(err, docs) {
    console.log(err); // --> { [MongoError: operation exceeded time limit] name: 'MongoError' }
});

operation exceeded time limit というメッセージのエラーが得られます。

このように、mongoose.Query オブジェクトを返すメソッドでmaxTimeメソッドが使えます。
Model#saveメソッド、Model#remove では残念ながら使えないようです。

エラーを判別しにくい問題

Errorオブジェクトにはエラー種別を明示的に判別するコードがありません。
そのため、とても不安な方法ですがエラーメッセージで判別する方法しか見当たりません(他に良い方法をご存知の方がおられましたらぜひご教授ください)。
メッセージによるタイムアウト判別は以下のようになります:

if(err.message === 'operation exceeded time limit') {
   // retry
}

なぜPHPにはMongoExecutionTimeoutExceptionがあるのにnode.jsでは無いんだ?

参考

投稿者:

Takuya

Digital crafts(man|dog). Love photography. Always making otherwise sleeping. born in 1984.

“[node.js] mongooseでクエリをタイムアウトさせるには” への 1 件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中