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


14

私は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を追加しますか?プロセスマネージャー専用の個別のイベントはありますか?これを行い、できるだけ乾燥した状態に保つ方法
  3. ProductReservedイベントのバスケットを知るにはどうすればよいですか?BasketIdそれらについても大丈夫ですか、それとも情報が漏れていますか?
  4. イベント間の関係を維持する方法、どのイベントがどのイベントをItemAdded生成したかをどのようにして知ることができProductReservedますか?に沿って渡しEventIdますか?これは奇妙に思えます...
  5. Basket単純な集計ではなく、プロセスマネージャとして実装する必要がありますか?

さらに調査を重ねた結果、「佐賀」は独自のイベントを保持し、外部からのイベントをリッスンするものです。基本的に、それは集合体であり、自身の小さな世界の外で発生するイベントにも反応することができます。

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


一連のコマンドで構成される既存の非公式のユースケースを言い換える正式なプロセスをシステムにエンコードしようとしているようです。そうすることで、既存のものに加えて多くの冗長なコマンドとイベントを作成しているように見えます。それはあなたの意図ですか?コードのプロセスとして物事を形式化する背後にあるビジネスニーズは何ですか?あなたのドメインでは、このプロセスとそれについての理由を完全な概念として特定する必要がありますか?
guillaume31

これは完全に構成されたプロジェクトであり、目的は2つの比較的独立した集約を連携させる方法を学習することです。したがって、実際の「ビジネスニーズ」はありません。また、これらのコマンドとイベントの冗長性を可能な限り回避しようとしています。そのため、プロセスマネージャーとの混乱。これは、集計が既に処理しているものを繰り返すべきではないようだからです。ただし、これら2つのアグリゲート間の接続を何らかの形で維持する必要があります。因果関係と相関関係を使用することが役立つようですが、試してみる必要があります。
イヴァンピンター

回答:


14

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

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

プロセスマネージャーを永続化する必要がありますか?私のように思えますが、よくわかりません

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

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

いいえ-プロセスマネージャはマネージャです。それ自体では何の役に立つこともしません。代わりに、作業を行う(つまり、記録帳に変更を加える)ように集合体に指示します。

ProductReservedイベントのバスケットを知るにはどうすればよいですか?それらにBasketIdを持つことは大丈夫ですか、それとも情報が漏れていますか?

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

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

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

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

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

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

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

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

ので、(私は「本当にいない」と言うの集計は、それが観察されたイベントのリストがという主張は完全に間違っていないということ漠然と十分に定義されている。我々はロード- 「集約」の違いは実装よりもセマンティックているプロセスの状態を、その後にどのようなメッセージを決めますドメイン状態の原因となるシステムの部分に送信します。ここで少し手を振っています。)

それで、PMは、リプレイ中にライブのことだけを担当するため、あるタイプの状態管理を別のタイプの管理に使用する必要はありませんか?

完全ではありません-状態管理は実行者ではなく、キーパートラッカーです。プロセスマネージャーが信号を発してはならない状況では、世界への不活性な接続を与えます。つまり、dispatch(command)ノーオペレーションです。


1
あなたは言う:あなたがそれを必要とするたびにイベントの履歴からプロセスマネージャを再構築することができます...しかし、それを再構築するために、私はそれのためにイベントを保存する必要があります。または、集計のイベントから再構築する必要がありますか?私が苦労しているのは、集約の場合、イベントに集約IDがあり、その集約IDを持つすべてのイベントを見つけることで簡単に再構築できることです。しかし、プロセスマネージャーに対してはどうすればよいでしょうか?プロセスマネージャーのためにそれを行うべきですか?または、プロセスマネージャーは、入ったイベントに基づいて何かを決定する必要があるときに集計を検索する必要がありますか?
イヴァンピンター

私が欠けていたのは、イベントの調達における因果関係と相関の概念でした。私がそれを調べたら、4番目の質問に対するあなたの答えはついに意味をなしました。
イヴァンピンター16年

1
@IvanPintarの最初のコメントに対する回答が欲しいです。プロセスマネージャーは集計を取得する必要がありますか?処理するイベントに基づいて独自に構築する必要がありますか?その場合、イベントハンドラーには副作用がない必要がありますよね?
ジェフ

@Jeff私が行った1つの例では、プロセスマネージャーは、処理された各イベントで更新された一種の読み取りモデルである独自のストレージを持っていました。これは簡単で、すでに処理されたものを追跡するのは簡単でした。別の例では、プロセスマネージャは、集約イベントから構築された独自のイベントを作成して保存しました。上記に似ていますが、状態はイベントソースです。プロセスマネージャが保持する状態の複雑さによっては、どちらかを行う方が簡単な場合があります。最初のアプローチがより簡単であることがわかりました。
イヴァンピンター

興味深いので、プロセスマネージャーがイベントに応答し、最終的にコマンドをディスパッチする限り、開発者次第ですか?
ジェフ

2

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

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

Sagasの素晴らしい記事はこちら

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.