web-dev-qa-db-ja.com

DDD、佐賀、イベントソーシング:補償アクションは、単にイベントストアの削除になりますか?

上記の質問はおそらくいくつかの「何ですか??」を引き起こすことに気づきましたが、説明させてください:

私はいくつかの関連する概念、つまり基本的にはSagaパターン( http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf )とEventの組み合わせに頭を抱えようとしています-ソーシング(A DDDの概念: 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に含まれる唯一の「ロジック」は、「プロセス」ロジック(ステートマシンとして実装されることが多い)です。これは、受け取ったアクション(およびフォローアップイベント)に基づいて、実行する処理(つまり、送信するアクティビティ)を決定します。
  4. Sagaパターンは、一種の分散トランザクションパターンを実装します。つまり、集約ルートの1つ(お互いの存在を知らなくても自律的に機能する)の1つが失敗すると、アクション全体をロールバックする必要がある場合があります。
  5. これは、佐賀への活動報告が完了すると、すべての集計ルートを持つことによって実装されます。 (成功およびエラーの場合)
  6. すべての集約ルートが成功を返す場合、佐賀が次に何をすべきかを決定する(またはそれが完了したと判断した)場合、内部ステートマシン
  7. 失敗した場合、佐賀は最後のアクションに参加したすべての集約ルートにいわゆる補正アクション、つまり各集約ルートが行った最後のアクションを元に戻すアクションを発行します。
  8. アクションが「プラス1投票」の場合、これは単に「マイナス1投票」を実行している可能性がありますが、ブログ投稿を以前のバージョンに復元するなど、より複雑になる可能性があります。
  9. イベントソーシング(2つを組み合わせたブログ投稿を参照)は、集約された各ルートが行う各アクティビティの結果を集中型のイベントストアに保存することを外部化することを目的としています(このコンテキストでは、変更は「イベント」と呼ばれます)。
  10. このイベントストアは「真実の単一バージョン」であり、格納されたイベント(基本的にイベントログのように)を繰り返すだけで、すべてのエンティティの状態を再生するために使用できます。
  11. 2つを組み合わせると(つまり、集約ルートがイベントソーシングを使用してアウトソーシングを行い、変更を保存してから佐賀に報告する)、多くのニースの可能性が可能になります。そのうちの1つは私の質問に関係しています...

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

質問:集約ルートが補償アクションを受け取ったとき、その集約ルートがアウトソーシングしている場合、イベントソーシングを使用して状態変更を行うと、補償は行われません。すべての状況でのアクションは、その特定の集約ルートのイベントストア内の最後のイベントの削除だけですか? (persist-implementationが削除を許可すると仮定)

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

これが長続きしないことを願っています。

ありがとう。

17
Geert-Jan

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

greg youngのカートの例と削除されたアイテムについて考えてみましょう。明日になるかもしれませんが、補償アクションの情報はどんな価値でもあります。

佐賀に関しては、私自身が知る限り、すべてが正しい。あなたは佐賀を状態機械のように考えるべきです。それだけです。

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

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

9
Arthis

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

自分自身を前方に再生するイベントだけでなく、自分自身を逆にできることもしばしば役立ちます。

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

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

差出人: http://martinfowler.com/eaaDev/EventSourcing.html

6
Geert-Jan

概念的に:

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

アプリケーションの状態を変更するイベントを発生させる別のコマンド(補正アクション)を実行することによってのみ、将来の状態を変更できます。

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

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

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

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

1
uvsmtid

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

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

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

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

ACIDデータベーストランザクション(コミット/ロールバックを伴うトランザクション)が妥当である場合、補正トランザクションが妥当でないのはなぜですか?

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

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

0
Paulo Merson

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

enter image description here ref: https://cambridge-intelligence.com/bringing-time-series-data-to-life-with-keylines/

Ofc。通常のサイトではこれは問題ではありませんが、これらのソリューションはfacebookやgoogleなどの巨大なWebサイト用に設計されています...つまり、追加のみのデータベースでイベントを削除する方法と、タイムマシンを構築し、時間を遡ってイベントを変更または防止するようなものを報酬と呼びますか???

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

0
inf3rno