web-dev-qa-db-ja.com

CQRS / ESでは、コマンドは別のコマンドを作成できますか?

CQRS/ESでは、コマンドはクライアントからサーバーに送信され、適切なコマンドハンドラーにルーティングされます。そのコマンドハンドラーは、そのリポジトリーから集約をロードし、その上のいくつかのメソッドを呼び出して、それをリポジトリーに保存します。イベントが生成されます。イベントハンドラー/佐賀/プロセスマネージャーは、コマンドを発行するためにこれらのイベントをリッスンできます。

そのため、コマンド(入力)はイベント(出力)を生成し、さらに多くのコマンド(入力)をシステムにフィードバックできます。さて、コマンドがイベントを発行せずに、別のコマンドをエンキューするのは一般的な習慣ですか?このようなアプローチは、外部プロセスでの実行を強制するために使用できます。

編集:

私が考えている特定のユースケースは、支払いの詳細の処理です。クライアントはPayInvoiceコマンドを送信します。そのペイロードにはユーザーのクレジットカードの詳細が含まれます。 PayInvoiceHandlerは、MakeInvoicePaymentコマンドを別のプロセスに渡します。このプロセスは、支払いゲートウェイとの対話を担当します。支払いが成功すると、InvoicePaidイベントが生成されます。何らかの理由でPayInvoiceコマンドが保持された後、MakeInvoicePaymentコマンドが保持される前にシステムがクラッシュした場合、これを手動で追跡できます(支払いは行われません)。 MakeInvoicePaymentコマンドが保持された後、InvoicePaidイベントが保持される前にシステムがクラッシュした場合、ユーザーのクレジットカードに請求が行われているが、請求書に支払い済みのフラグが付けられていない可能性があります。 。その場合、状況を手動で調査し、請求書に手動で支払い済みのマークを付ける必要があります。

9
magnus

振り返ってみると、私は問題を複雑にしていたと思います。

一般に、コマンドは例外をスローするか、1つ以上のイベントを発生させる必要があります。

イベントソーシングのアーキテクチャを要約すると、次のようになります。

  • コマンドは、何かをするための指示を表す入力です。
  • イベントは、行われたことの歴史的事実を表す出力です。
  • イベントハンドラーは、コマンドを発行するためにイベントをリッスンして、システムのさまざまな部分を調整することができます。

あるコマンドが別のコマンドを作成すると、コマンドとイベントの一般的な意味が曖昧になります。あるコマンドが別のコマンドを「トリガー」する場合、そのコマンドは「行われたことの歴史的事実」であることを意味します。これはこれら2つのタイプのメッセージの意図と矛盾し、他の開発者がイベントからイベントをトリガーし、データの破損や最終的にinconsistencyにつながる可能性があるという点で、滑りやすい経路になる可能性があります。

私が提起した特定のシナリオに関して、複雑な要因は、メインスレッドが支払いゲートウェイと対話することを望まないことでした(これは、永続的なシングルスレッドプロセスであるため)、他のコマンドを処理できないためです。 。ここでの簡単な解決策は、別のスレッド/プロセスを生成して支払いを処理することです。

説明のために、クライアントはPayInvoiceコマンドを送信します。 PayInvoiceHandlerは新しいプロセスを開始し、支払いの詳細を渡します。新しいプロセスは支払いゲートウェイと通信します。支払いが成功した場合は、領収書番号(InvoicePaidイベントを生成)を使用してinvoice.markAsPaid()を呼び出します。支払いが失敗した場合、さらに調査するための参照コードを渡してinvoice.paymentFailed()を呼び出します(これによりInvoicePaymentFailedイベントが生成されます)。したがって、別のプロセス/スレッドが関係しているという事実にもかかわらず、パターンはCommand -> Eventのままです。

失敗に関しては、3つのシナリオがあり、PayInvoiceコマンドが持続した後、InvoicePaidまたはInvoicePaymentFailedイベントが持続する前に、システムがクラッシュする可能性があります。この場合、ユーザーのクレジットカードに請求されたかどうかはわかりません。このような場合、ユーザーはクレジットカードの請求に気づき、苦情を申し立てます。その場合、スタッフメンバーが問題を調査し、手動で請求書に支払い済みのマークを付けることができます。

11
magnus

コマンドからイベントを発行するだけの場合、アーキテクチャ的にはより疎結合なシステムになります。別の言い方をすれば、1つのコマンドが他に発行する外部コマンドを認識する必要はありません。これは外部の当事者の責任である必要があります(イベントにサブスクライブする必要があり、先に述べたように、調整の責任を持つ佐賀マネージャー、またはこれらのイベントに依存する別のモジュールのみが考えられます)。

3
Erik Eidt

推奨される表示: Reliable Messaging -のUdi Dahan-これは、あなたが説明しているものとはまったく異なりますが、密接に関連しています。

さて、コマンドがイベントを発行せず、別のコマンドをエンキューするのは一般的な慣行ですか?

私はそのようなやり方を勧める人を見たことがありません。

短い答え:状態を保存しないと、エンキューされたコマンドを受け取ったことを確認した後でクラッシュした場合、エンキューされたコマンドを回復できません。

状態を保存する必要があると判断した場合、イベントハンドラーを使用するのではなく、最初から2番目のコマンドをスケジュールすることには大きな利点があることは明らかではありません。

2
VoiceOfUnreason