状況を想像してみてください。
var txn = new DatabaseTransaction();
var entry = txn.Database.Load<Entry>(id);
entry.Token = "123";
txn.Database.Update(entry);
PublishRabbitMqMessage(new EntryUpdatedMessage { ID = entry.ID });
// A bit more of processing
txn.Commit();
これで、EntryUpdatedMessage
のコンシューマーは、このメッセージを受け取る可能性がありますbeforeトランザクションtxn
がコミットされているため、更新を確認できません。
これで、RabbitMQがそれ自体でトランザクションをサポートすることはわかっていますが、公開ごとに新しいIModel
を作成し、スレッドごとのモデルを作成するのは非常に面倒なので、実際には使用できません(ASP.NET Web応用)。
DBトランザクションがコミットされたときに公開される予定のメッセージのリストを作成することを考えましたが、それは本当に臭い解決策です。
これを処理する正しい方法は何ですか?
RabbitMQでは、トランザクションではなく発行者の確認を使用することをお勧めします。トランザクションはうまく機能しません。
いずれにせよ、トランザクションは通常、サービス指向アーキテクチャーではうまく機能しません。 「結果整合性」アプローチを採用することをお勧めします。このアプローチでは、障害を後日再試行でき、重複するべき等メッセージは無視されます。
あなたの例では、メッセージを公開する前にデータベースの更新とコミットを行います。出版社が返品を確認したら、データベースレコードのフィールドを更新して、メッセージが送信されたことを示します。その後、スウィーパープロセスを実行し、未送信のメッセージをチェックして、途中で送信することができます。メッセージが通過したが、何らかの理由で確認または後続のデータベース書き込みが失敗した場合は、重複したメッセージが表示されます。ただし、メッセージがべき等になるように設計されているため、それは問題ではありません。