ドメインイベントをトランザクション内外で提起する必要がありますか?
-
11-10-2019 - |
質問
アプリケーションでは、ドメインモデルに何かが変更されたときにドメインイベントを提起します。イベントハンドラーによって実行されるタスクの一部は、イベントが発生したときに使用されたのと同じトランザクション内で行う必要があります。他のタスクは、このトランザクション以外で実行する必要があります。
例えば、
Order -LineがOrderエンティティに追加されると、OrderLineadded Domainイベントが発生すると、1つのドメインイベントがドメインモデルの状態を変更します(同じトランザクションで実行する必要があります)、トランザクションが完了するとUIを更新する必要があります。
この問題にどのようにアプローチしますか?
- トランザクション内の2つのイベントと、トランザクションの外側に1つのイベントを提起します。
- トランザクション内でイベントを提起しますが、イベントハンドラーを使用して非同期リクエストを送信してUIを更新しますか?
オプション1は、イベント名が何らかの形でトランザクションの内外であることを伝える必要があるため、混乱しているようですが、ドメインイベントのオプション2ハンドラーは、トランザクション内から同期的に呼ばれると常に想定する必要があります。
多分より良いアプローチがありますか?
解決
同様の問題がありました。ドメインモデルはイベントを公開していました(Udi Dahanが説明する手法を使用してください ここ)。それから、何かがうまくいかず、トランザクションが後で戻ってきたとしても、UI関連のハンドラーが呼び出されることに気付きました。
これを修正するために、私はシステムに別の役割、別の種類のイベントハンドラーを紹介しました。私が持って ITransactionalEventHadneler
と INonTransactionalEventHandler
. 。前者はすぐに同期的に呼び出されました DomainEvents.Publish()
方法。後者は、トランザクションがコミットされるとすぐに呼び出されるようにキューにされました(System.Transactionsフックを使用)。ソリューションは正常に機能し、非常に読みやすく保守可能でした。
他のヒント
両方のアプローチが良いと思います。コードのすべての部分で同じアプローチに固執するだけです。
- 2つ(またはそれ以上)のイベントハンドラーが必要です。1つは、UIのような補助コンテキストのトランザクションスコープ内にあるドメインモデルのコンテキスト用と、その他のコンテキスト用です。ドメインコードは、コードの他の部分が何をするかを気にしないでください。ドメインデータの変更について通知するだけです。
- ドメインコードイベントハンドラーメソッドは、UIまたは他のモジュールに非同期イベントを送信する場合があります。ドメインイベントは同期する必要があります。そうしないと、取引性を維持するために2フェーズコミットが必要です。
ドメインコードクリーナーを維持し、非同期通信を使用することにより、コアや他のモジュールが分離されるため、外部モジュールの問題はコアの動作を妨げないため、オプション2がさらに好きです。一方、オプション1がより有利な状況がある場合があります。