DDD、Saga、およびイベントソーシング:補償アクションは、イベントストアで単に削除できますか?


15

上記の質問はおそらくいくつかの「何??」を発生させることを理解していますが、説明しよう:

私は、いくつかの関連する概念、基本的にはSaga-pattern(http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf)とEvent-sourcing(A DDD-concept)に頭を包み込もうとしています。http : //en.wikipedia.org/wiki/Domain-driven_design

まとめた良い投稿:https : //blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/

私はすぐに質問に近づいていますが、最初にそれについて理解していることを要約しようとする必要があると思います(これは間違っている可能性がありますので、その場合は修正してください)次から始まる質問をする:

  1. Sagaパターンは、アクション(エンドユーザー、自動化など、本質的にデータを変更するもの)を指定したブローカーの一種で、そのアクションをビジネスアクティビティに分割し、これらの各アクティビティをメッセージとしてメッセージバスに送信します。次に、それをそれぞれの集約ルートに送信して処理します。
  2. これらの集約ルートは完全に自律的に動作できます(懸念事項の分離、優れたスケーラビリティなど)。
  3. Sagaインスタンス自体には、ビジネスロジックが含まれていません。ビジネスロジックは、アクティビティを送信する集約ルートに含まれています。佐賀に含まれる唯一の「ロジック」は「プロセス」ロジック(多くの場合Statemachineとして実装されます)で、受信したアクション(およびフォローアップイベント)に基づいて何を行うか(つまり、どのアクティビティを送信するか)を決定します
  4. Saga-patternsは、一種の分散トランザクションパターンを実装します。つまり、集約ルートの1つ(相互の存在を認識せずに自律的に動作する)の1つが失敗した場合、アクション全体をロールバックする必要があります。
  5. これは、佐賀へのアクティビティレポートの完了時に、すべての集約ルートを持つことで実装されます。(成功とエラーの場合)
  6. すべての集約ルートが成功を返す場合、佐賀が次に何をすべきかを決定する(または完了したと判断する)場合、内部ステートマシン
  7. 失敗した場合、佐賀は、最後のアクションに参加したすべての集約ルートに対して、いわゆる補償アクション、つまり、各集約ルートが行った最後のアクションを取り消すアクションを発行します。
  8. アクションが「プラス1票」の場合、これは単に「マイナス1票」を実行することですが、ブログポストを以前のバージョンに復元するなど、より複雑になる可能性があります。
  9. イベントソーシング(2つを組み合わせたブログ投稿を参照)は、集約された各ルートが行う各アクティビティの結果を一元化されたイベントストアに保存することを外部化することを目的としています(このコンテキストでは変更は「イベント」と呼ばれます)
  10. このイベントストアは「真実の単一バージョン」であり、保存されたイベントを繰り返すだけで(本質的にイベントログのように)すべてのエンティティの状態を再生するために使用できます。
  11. 2つを組み合わせること(つまり、集約ルートがイベントソーシングを使用して変更を保存し、佐賀に報告する前に変更を保存する)により、多くの素晴らしい可能性が可能になります。

これを一度に把握するのは大変なので、肩から離す必要があると感じました。このコンテキスト/マインドセットが与えられます(もう一度、間違っている場合は修正してください)

質問:集約ルートが補正アクションを受信し、その集約ルートがイベントソーシングを使用した状態変更を外部委託している場合、すべての状況での補正アクションは、そのイベントストアの最後のイベントの削除だけではありません集約ルートを指定しますか?(persist-implementationが削除を許可すると仮定)

それは私にとって非常に理にかなっています(そしてこの組み合わせのもう一つの大きな利点です)が、私が言ったように、これらの概念の誤った/不完全な理解に基づいてこれらの仮定をしているかもしれません。

これが長すぎないことを願っています。

ありがとう。

回答:


9

イベントストアからイベントを削除しないでください。これらは起こったことを表しています。今何かが起こった場合は、それも知っておく必要があります。したがって、集約を強制的に前の状態に戻すイベントを追加します。データベースから情報を削除するのは残念です。

グレッグヤングのカートと削除されたアイテムの例を考えてください。明日かもしれませんが、補償措置の情報はどんな価値があるかもしれません。

サガに関しては、私が知っている限り、すべてのものが正しい。サガはステートマシンと考える必要があります。それだけです。

それは、サガが発行するコマンドであり、集合体に何かをするように伝えます。このアクションのイベントがあります。このイベントは、必要な修正アクションである場合があります。または、ビューで非正規化して、何をすべきかを決定するために一部のユーザーが表示する必要がある場合があります。

それはあなたのビジネスルールに依存します。どちらか、簡単な修正があります:集約ルートは、そのような場合、あなたがそれを行うこと、または選択がプログラムで実行するには複雑すぎる(開発コストが高すぎる)ことを知っているので、これを一部のユーザーに提案するかもしれません異なるアクションから選択できます。すべては、補正アクションのコンテキストに依存します。これは純粋なビジネスルールです。この場合またはその場合、何をすべきか。これは、ドメインエキスパートに尋ねてから、自動ソリューションを開発する方が良い場合、またはユーザーRonald R.に尋ねるのが通常ならこの質問に答える方がいい場合、彼と一緒に選択するものです。


アグリゲートはどの状態に戻すかをどのように知るのでしょうか?イベントストアなどに対してクエリを実行できますか?
Geert-Jan

元に戻すのではなく、別のイベントを追加する必要があります。それは、サガが発行するコマンドであり、集合体に何かをするように伝えます。このアクションのイベントがあります。
Arthis

うん分かりました。「元に戻す」は、おそらく不適切に選択されました。次のことを考慮してください。ドキュメント発行/承認フローなどのモデリングのために、SagasでEvent Sourcingを使用したい場合があります。最終的にBlogBodyChanged-eventとしてイベントストアに永続化されるChangeBlogBody-actionをエディターが送信した場合はどうなりますか。その後、何らかの理由で、補償アクションが発行されます。Aggregateは、ChangeBlogBody-actionが発行される直前のように、Blog Bodyのコンテンツを発生させる、発生する補正イベントをどのように知るのでしょうか?
Geert-Jan

それはあなたのビジネスルールに依存します。どちらか、簡単な修正があります:集約ルートは、そのような場合、あなたがそれを行うことを知っているか、選択が複雑すぎてプログラムで行うことができない(開発コストが高すぎる)ので、これを一部のユーザーに提案するかもしれません異なるアクションから選択できます。
Arthis

すべては、補正アクションのコンテキストに依存します。これは純粋なビジネスルールです。この場合またはその場合、何をすべきか。これは、ドメインエキスパートに尋ねてから、自動ソリューションを開発する方が良い場合、またはユーザーRonald R.に尋ねるのが通常ならこの質問に答える方がいい場合、彼と一緒に選択するものです。
アルティス

6

完全を期すために、状態を元に戻す方法に関するMartin Fowlerの関連するスニペットを含めると考えました。

イベント自体が順方向に再生されるのと同様に、イベントを逆方向に戻すこともできます。

イベントが差の形でキャストされる場合、反転は最も簡単です。この例は、「Martinのアカウントを110ドルに設定する」のではなく、「Martinのアカウントに10ドルを追加する」です。前者の場合、$ 10を差し引くだけで元に戻すことができますが、後者の場合、アカウントの過去の価値を再現するのに十分な情報がありません。

入力イベントが差分アプローチに従わない場合、イベントは処理中の反転に必要なすべてを保存することを保証する必要があります。これを行うには、変更された値に以前の値を保存するか、イベントの差を計算して保存します。

から:http : //martinfowler.com/eaaDev/EventSourcing.html


1

概念的に:

  • イベントは何が起こったかです。過去を変えることはできません。
  • コマンドはやるべきことです。コマンドが発生しない場合があります(拒否される場合があります)。

将来の状態を変更するには、別のコマンド(補償アクション)を実行する必要があります。これにより、イベントがアプリケーションの状態を変更します。

質問を「混乱させない」ために、「最後のイベントの削除」というフレーズを考えてください。

  • 最後のイベントが削除する必要のあるイベントではない場合はどうなりますか?削除するイベントの後に他のイベントが発生した場合はどうなりますか?これらのイベントも変更する必要があります(それらのイベントの前にイベントを削除すると、基本状態が変更されるため)。
  • イベントが外部システムに送信された場合はどうなりますか?別のイベントを送信する以外、その状態を修正するアクセス権がない場合があります。

つまり、CQRSパターン内のイベントを削除するオプションはありません。

スナップショット状態(その状態に至るすべてのイベントに基づく)を作成することでイベントストアを縮小できますが、この物理的な側面はイベントの概念とは関係ありません。


0

Geert-Jan、私も補償アクションは単に対応するイベントを削除できると思います。それは理にかなっており、イベントソーシングのデザインパターンのもう1つの利点を示しています。それは、補償トランザクションデザインパターンのより簡単な実装です。

イベントを削除すると、イベントソーシングまたはCQRSの「原則」に違反すると言う人もいます。それは限定的な一般化だと思います。キャンセルされるグローバルトランザクションのスコープ内で作成されたイベントを削除しても問題ないと思います。擬似コードを検討してください。

try {
    newEvents = processMycommand(myCommand)
    for (Event newEvent : newEvents)
        EventStore.insertEvent(newEvent);
} catch (Exception e) {
    EventStore.rollback();
}

イベントストアがトランザクションデータベースであるとします。擬似コードでは、最初のイベントを挿入した状況を想像できますが、2番目のイベントを挿入しようとすると例外がスローされました。rollbackコマンドは、最初のイベントの挿入を自然に元に戻します。それは合理的ですか?

ACIDデータベーストランザクション(コミット/ロールバックを伴うトランザクション)にとって合理的である場合、なぜ補償トランザクションとして合理的ではないのでしょうか?

グローバルな佐賀トランザクションを実行するとき、データの変更は元に戻すことができます(補償により)。トランザクションが完了しなかったため、トランザクション中に作成されたイベントを保持する必要はありません。

これで、補正がイベントを削除しようとして、そのイベントがオブジェクトの最新のイベントでない場合、削除は発生しません。しかし、一般的に、特に読み取り集中型のソリューションでは、これは起こりそうにありません。


0

イベントストレージは保存したい単なるデータであると考えてみましょう。たとえば、ハードドライブを使用して、最初から開始してデータを書き込むことができます。イベントが発生するたびに以前のデータを追加するため、前回停止したディスクに書き込みを続けます。イベントを削除する場合は、戻って、ディスクからその部分を削除し、ギャップを残します。それ自体に戻ると、イベントの保存が遅くなりますが、それで生きることができます。ファイルシステムを使用すると、後者のイベントでギャップを埋めようとするため、ストレージの断片化が遅くなるか、デフラグを実行できます。どちらも私たちが好きなものではありません。データベースについて話している場合、イベントの保存に追加専用データベースではなくリレーショナルデータベースを使用すると、これが得られます。

ここに画像の説明を入力してください ref:https : //cambridge-intelligence.com/bringing-time-series-data-to-life-with-keylines/

Ofc。通常のサイトではこれは重要ではありませんが、これらのソリューションはfacebook、googleなどのような巨大なWebサイト向けに設計されています。タイムマシンを構築し、イベントを変更または防止するために時間をさかのぼるなど、補償と呼びますか?

私の知る限り。これを解決する唯一の方法は、不要なイベントを除外する新しいイベントストレージを作成し、その後、古いイベントストレージを削除することです。しかし、これは単一のイベントを削除する極端なソリューションです。GDPRについて話している場合、私が知っている唯一の比較的良い解決策は、イベントストレージに暗号化された個人データを保存し、別のデータベースから暗号化キーを削除することです。

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