2015年7月1日水曜日

Mongoose の autoreconnect が動かない

やったことのメモ

Mongoose には自動再接続の機能があるらしいのだが思ったように動かない。

とりあえず connection の connected, disconnected, reconnected イベントを拾ってログを出すようにしてみたら、1回目の再接続時はきちんと disconnected → connected のイベントが出ていたが、2回目以降は disconnected は発生せずに reconnected だけ発生していた。

さらにややこしいのが一度でもデータベースに save をするとどのイベントも発生しなくなる(厳密には拾い方が変わるのかもしれんが)。readyState も変わらないのでどうしようも無い。

こちらのイベント処理が悪いのかと思って、autoreconnect を信じて全てのイベント処理を外してみても駄目。

バグなのか仕様なのか自分の使い方が悪いのかはわからんが、色々試行錯誤した結果以下のように save のコールバックで失敗した書き込みをキューイングして再接続させるようにしたらうまく動いた。

mongoose.connect(dbURI);

// 送信失敗したデータを溜めるためのキュー
var instQueue = [];
var connecting = false;

function saveInst(inst) {
  inst.save( function(err) {
    if(err) {
      console.log('save failed');
      instQueue.push(inst);
      if(connecting) {
        connecting = true;
        mongoose.connect(dbURI, function(err) {
          connecting = false;

          // 接続に成功したら溜まっているキューを save
          if(!err && instQueue.length > 0) {
            saveInst(instQueue.shift());
          }
        });
      }
    } else {
      console.log('saved');

      // キューが溜まっていれば残りも save
      if(instQueue.length > 0) {
        saveInst(instQueue.shift());
      }
    }
}

connect 中にもう一回 connect するとエラーになるので connecting フラグを使って多重コネクトを行わないように管理していたが、自前でフラグを作らずに readyState を見ても良かったかもしれない。

今回は定期的に吐かれるログを保存するためのスクリプトだったので接続に失敗してもキューに突っ込んでおいて次回リトライできるが、そうでない場合は setTimeout 等を使って手動で connection を何度もリトライする必要が出てくる。

でもそれホントは autoreconnect の仕組みがやってくれるはずなんだよね・・・

0 件のコメント:

コメントを投稿