MongoDBを使用した2フェーズコミットアプローチを検討することも、トランザクションを完全に忘れて、サービスバスアプローチを介してプロセスを分離することもできます。例としてAmazonを使用します-注文を送信することはできますが、在庫アイテムを確保したり、カードに請求したりするまで、確認は行われません。これは1回のトランザクションでは発生しません-これは単独で発生する可能性があり、必要に応じて補正ステップを適用できる一連のステップ。
ナイーブなバスの実装は次のことを行います(これは作業を行うための一般的な提案であり、正確な実装は同時実行性などの特定のニーズに依存することに注意してください)。
- 注文をキューに入れます。この時点で、引き続きクライアントを待機させるか、注文に感謝して、処理時に電子メールを受信することをクライアントに知らせることができます。
- 「在庫作業員」は注文を取得し、予約する必要のある在庫アイテムをロックします。これは、さまざまな方法で実行できます。Mongoを使用すると、orderidごとにドキュメントを持つコレクションを作成できます。このドキュメントのIDには、在庫アイテムIDと妥当なTTL(たとえば、30秒)が含まれます。ワーカーがロックを持っている限り、ロックを持っているアイテムの在庫レベルを管理できます。変更を加えると、「ロック」ドキュメントが削除される可能性があります。
- ロックされている間に同じアイテムを管理したい別のワーカーが来た場合は、ブロックされたワーカーをX秒間スリープモードにしてから再試行するか、リクエストをメッセージバスに戻してピックアップすることができます。後で別の労働者によって。
- ワーカーがすべての在庫アイテムを解決すると、カードに請求する必要があることを示す別のメッセージをサービスバスに配置するか、処理で在庫をプルする通知を受信するか、作成者に電子メールを送信できます。注文など
複雑に聞こえますが、メッセージバスを設定すると、実際には比較的単純になります。 ノードメッセージバスの実装のリストは、ここにあります。
一部の開発者は、正式なメッセージバスを完全にスキップし、単純な実装で機能するメッセージパッシングエンジンとしてデータベースを使用することさえあります。GoogleMongoとキュー。
複数のサーバーを期待せず、メッセージバスの実装が大きすぎる場合は、ノードがロックとメッセージパッシングを処理できます。たとえば、本当にノードでロックしたい場合は、在庫アイテムIDを格納する配列を作成できます。とはいえ、率直に言って、メッセージバスが最善の方法だと思います。とにかく、Nodeで単純な外部リソースロックを処理するために過去に使用したコードを次に示します。
// attempt to take out a lock, if the lock exists, then place the callback into the array.
this.getLock = function( id, cb ) {
if(locks[id] ) {
locks[id].push( cb );
return false;
}
else {
locks[id] = [];
return true;
}
};
// call freelock when done
this.freeLock = function( that, id ) {
async.forEach(locks[id], function(item, callback) {
item.apply( that,[id]);
callback();
}, function(err){
if(err) {
// do something on error
}
locks[id] = null;
});
};