generated at
MongoDB Unified Topology


mongodb native driver 3.3以降で使われる接続仕様

根本的に接続周りの仕様が変わる
接続/切断モデルはcluster環境下では適さないから廃止する
これまでのmongodb clientは、DBと接続されている / 接続されていないで動作を変えていた
「接続されている」の定義が曖昧だった
primaryに接続した時点でtrue?
その後secondaryにも接続した?
全nodeのステータスを取得完了した?
primaryとsecondaryの切り替え中は?
など
まとめて「サーバー選択中」というstateで扱う
サーバー選択中は全てのDBのread/writeをブロッキングし、接続復旧を待って実行する
model.find() model.save() もAPIは変更なし。これまで通りawaitするだけでいい
サーバー選択が長すぎる場合はタイムアウトする
serverSelectionTimeoutMS で指定する


mongoose 5.7.0あたりからdeprecation warningが出る
> DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to MongoClient.connect.
nodeのwarningってどこから出てるかわかりにくいけど、これはmongo native driver npmが出していますshokai
解消方法
MongoDB接続よりも前にフラグを立てる
mongoose.set('useUnifiedTopology', true)
もちろんwarningを消すだけでなく、接続オプションや、切断時の例外処理は見直さなければならない

接続・切断周りの仕様の違い
DBが接続されるまでの間、readもwriteもブロックされる
こういうコードが正しく動く事を目指しているらしい
Unified Topology DesignのBehavioral Changesより
js
const client = new MongoClient('mongodb://llama:drama@localhost:27017/?replicaSet=rs'); const coll = client.db('test').collection('foo'); await coll.insert({ test: 'document' }); const docs = coll.find({ test: 1 }, { readPreference: 'secondary' }).toArray(); console.dir({ docs }); await client.close();
ポイント
client作っていきなりinsertする
接続完了をawaitで待ったりしていない
insert自体はawaitする
接続完了するまでinsertがブロックする
find.toArrayにawait付けてない
これは意図がよくわからないshokai
await忘れてるだけ?
promiseのtoArrayに何か特別な機能がある?
awaitもcallbackもpromiseも使わずに、なぜか同期的にデータが読める?
MongoClient.isConnected の廃止
廃止されるまで、しばらくは常にtrueが返るらしい
豪快だshokai
たぶんmongodbを扱うmiddlewareへの配慮だろう。connect-mongoとか
unified topologyを選択した場合、 connectTimeoutMS オプションは何もしなくなった
mongoose 5.9.8のchangelogには、 代わりに serverSelectionTimeoutMS を使えと書かれている
しかしこの2つは代替ではなさそうshokai
切断
Unified Topology DesignのdisconnectHandlerより
primaryへのinsert/update中にprimaryが切断
その後いろいろなパターンがある
primaryがすぐ復帰する
secondaryに切り替わる(failover)
primaryがsecondaryに格下げ
primaryがshutdownする
その全ての状態でのタイムアウトとリトライを serverSelectionTimeoutMS で表現する
なるほど、だから isConnected connectTimeoutMS もダメなのかshokai