web-dev-qa-db-ja.com

イベントソーシングでプロセスマネージャを実装する方法

CQRSとイベントソーシングの概念を学ぶために、小さなサンプルアプリケーションに取り組んでいます。独立して動作するBasket集約とProduct集約があります。

以下は、実装を示すための擬似コードです。

Basket { BasketId; OrderLines; Address; }

// basket events
BasketCreated { BasketId; }
ItemAdded { BasketId; ProductId; Quantity }
AddItemSucceeded { BasketId; ProductId; Quantity }
AddItemRevoked { BasketId; ProductId; Quantity }
ItemRemoved { BasketId; ProductId; Quantity }
CheckedOut { BasketId; Address }

Product { ProductId; Name; Price; }

// product events
ProductReserved { ProductId; Quantity }
ProductReservationFailed { ProductId; Quantity }
ProductReservationCancelled { ProductId; Quantity; }

コマンドはイベントに非常によく似ており、過去形ではなく命令名を使用します。

現在、これらは独立して問題なく動作します。コマンドAddItemを発行すると、ItemAddedアグリゲートにBasketイベントが作成され、「バスケット」の状態を処理する必要があります。同様に、製品の場合、コマンドとイベントは問題なく機能します。

これを、次のようなプロセスに結合したいと思います(発生するコマンドとイベントに関して):

プロセスマネージャは次のことを行います。

on BasketCreated: CreateShoppingProcess
on ItemAdded: ReserveProduct
on ProductReserved: SucceedAddingItem // does nothing, but needs to be there so that the basket knows it can check out
on ProductReservationFailed: RevokeAddItem
on RemoveItem: CancelProductReservation
on Checkout: CreateOrder // create an order and so on...

決定的な答えを見つけることができなかった質問は次のとおりです。

  1. プロセスマネージャを永続化する必要がありますか?しているようですが、よくわかりません
  2. その場合、プロセスマネージャのイベントを保存する必要があります。ただし、リッスンしているイベントは集計に関連付けられています。それらにプロセスIDを追加しますか?プロセスマネージャー専用のイベントはありますか?これを行い、DRYを可能な限り維持する方法
  3. ProductReservedイベントの対象となるバスケットを知るにはどうすればよいですか?それらにBasketIdを付けても大丈夫ですか、それとも情報が漏洩していますか?
  4. イベント間の関係を維持する方法、どのItemAddedがどのProductReservedイベントを生成したかを知るにはどうすればよいですか? EventIdを渡しますか?これは奇妙に思えます...
  5. Basketを単純な集計ではなくプロセスマネージャーとして実装する必要がありますか?

もう少し調査した後、私はこれに行きました:佐賀はそれ自身のイベントを保持し、外部からのイベントを聞くものです。基本的に、それは自身の小さな世界の外で起こっている出来事にも反応することができる集合体です。

プロセスマネージャーは、外部からのイベントを処理し、コマンドを送信します。その履歴は、correlationIdのような共通の識別子を共有するAggregatesで発生したイベントから再構築できます。

16
Ivan Pintar

Rinat Abdullinが 進化するビジネスプロセス について書いた内容を確認します。特に、急速に変化する環境でビジネスプロセスを開発するための彼の推奨事項に注意してください。プロセスマネージャーは、画面を見つめる人間の代わりに自動化された「単なる」ものです。

私自身のプロセスマネージャーのメンタルモデルは、保留中のコマンドのリストを照会できるのはイベントソースプロジェクションです。

プロセスマネージャを永続化する必要がありますか?しているようですが、よくわかりません

読み取りモデルです。必要になるたびに、イベントの履歴からプロセスマネージャを再構築できます。または、更新したスナップショットのように扱うこともできます。

その場合、プロセスマネージャのイベントを保存する必要があります。

いいえ-プロセスマネージャはmanagerです。それ自体は何の役にも立ちません。代わりに、アグリゲートに機能するように指示します(つまり、記録簿に変更を加えます)。

ProductReservedイベントのバスケットを知るにはどうすればよいですか?それらにBasketIdを設定しても問題ありませんか、それとも情報が漏洩していますか

承知しました。 注:ほとんどの「実際の」ショッピングドメインでは、注文を処理する前に在庫を予約する必要はありません。ビジネスに不要な競合を追加します。あなたのビジネスが注文を受け入れることを望んでいる可能性が高いですが、注文が必要な時間内に満たされないというまれなケースでは謝罪します。

イベント間の関係を維持する方法、どのItemAddedがどのProductReservedイベントを生成したかを知るにはどうすればよいですか?

メッセージにはメタデータがあります。特に、causationIdentifier(どのコマンドがどのイベントを生成したかを識別できるようにする)と correlationIdentifier を含めて、一般的に会話を追跡できます。

たとえば、プロセスマネージャは独自のIDをコマンドのcorrelationIdとして書き込みます。コマンドの相関IDのコピーによって生成されたイベント。プロセスマネージャーは、独自のcorrelationIdを持つすべてのイベントをサブスクライブします。

バスケットを単純な集計ではなくプロセスマネージャとして実装する必要がありますか?

私の推薦はノーです。 しかしUdi Dahanはあなたが見直すべき異なる意見を持っています。つまり、 CQRSは、集計がサガの場合にのみ意味があります -Udiは、プロセスマネージャーが主要なスペルになった場所でサガを使用しました。

プロセスマネージャは集計を取得する必要がありますか?

あんまり?プロセスマネージャは、主にドメインの状態ではなく、オーケストレーションに関係しています。プロセスのインスタンスには、観察したすべてのイベントの履歴という形で「状態」があります。イベントZに応答して行う正しいことは、イベントXとYを見たかどうかによって異なります。 。そのため、その状態の表現を格納およびロードできる必要がある場合があります(これは、フラットなものである場合もあれば、観測されたイベントの履歴である場合もあります)。

(私は「本当ではない」と言います(なぜなら、aggregateは、観測されたイベントのリスト 「集約」。違いは実装よりも意味的です-プロセスの状態をロードし、システムの責任のある部分に送信するメッセージを決定しますdomain stateここで少し手を振っています。)

つまり、PMは、ライブでのみ行い、リプレイ中には責任を負わないため、あるタイプの状態管理を別のタイプの管理に使用する必要はありませんか?

完全ではありません-状態管理は実行するものではなく、キーパートラッカーです。プロセスマネージャーがシグナルを発行してはならない状況では、プロセスマネージャーにワールドへの不活性な接続を与えます。つまり、dispatch(command)は何もしません。

15
VoiceOfUnreason

あなたが探しているものは、「佐賀」と呼ばれるパターンを持っています。それは本質的にプロセスマネージャーです。

Sagaは相関するコマンド間の状態を維持できるため、長時間実行するプロセスにも最適です。

これはSagasに関するすばらしい記事です

3
Bishoy