DDD, Saga et sourcing d'événements: une action de compensation peut-elle être simplement une suppression sur le magasin d'événements?

15

Je me rends compte que la question ci-dessus soulève probablement quelques «quoi», mais laissez-moi essayer d'expliquer:

J'essaie d'envelopper ma tête sur quelques concepts connexes, essentiellement le modèle Saga ( http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf ) en combinaison avec Event-sourcing (Un concept DDD : http://en.wikipedia.org/wiki/Domain-driven_design )

Un bon article qui le regroupe: https://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/

J'arrive à la question dans une minute, mais je pense que je dois essayer de résumer ce que je comprends d'abord (ce qui pourrait bien être faux, alors veuillez corriger si c'est le cas) car cela pourrait bien avoir un impact sur la raison pour laquelle je suis poser la question pour commencer:

  1. Le modèle Saga est une sorte de courtier qui, étant donné une action (utilisateur final, automatisé, etc. essentiellement tout ce qui va changer les données), divise cette action en activités commerciales et envoie chacune de ces activités sous forme de messages à un bus de messages qui à son tour l'envoie aux racines agrégées respectives à prendre en charge.
  2. Ces racines agrégées peuvent fonctionner de manière totalement autonome (belle séparation des préoccupations, grande évolutivité, etc.)
  3. Une instance Saga elle-même ne contient aucune logique métier, qui est contenue dans les racines agrégées auxquelles elle envoie des activités. La seule «logique» contenue dans la saga est la logique de «processus», (souvent implémentée comme une machine à états), qui détermine en fonction des actions reçues (ainsi que des événements de suivi) ce qu'il faut faire (c'est-à-dire: quelles activités envoyer)
  4. Les modèles Saga implémentent une sorte de modèle de transaction distribuée. C'est-à-dire: lorsque l'une des racines agrégées (qui fonctionnent à nouveau de manière autonome, sans se connaître mutuellement) échoue, l'action entière peut devoir être annulée.
  5. Ceci est mis en œuvre en ayant toutes les racines agrégées, à la fin de leur rapport d'activité à la Saga. (En cas de succès ainsi que d'erreur)
  6. Dans le cas où toutes les racines agrégées retournent un succès, la statemachine interne si la Saga détermine quoi faire ensuite (ou décide que c'est fait)
  7. En cas d'échec, la Saga envoie à toutes les racines agrégées qui ont participé à la dernière action une action dite de compensation, c'est-à-dire: une action pour annuler la dernière action effectuée par chacune des racines agrégées.
  8. Cela pourrait simplement faire un «vote moins 1» si l'action était «plus 1 vote», mais cela pourrait être plus compliqué comme restaurer un blog à sa version précédente.
  9. L'événementiel (voir le blog combinant les deux) vise à externaliser la sauvegarde des résultats de chacune des activités que chacune des racines agrégées entreprend dans un magasin d'événements centralisé (les changements sont appelés «événements» dans ce contexte)
  10. Ce magasin d'événements est la «version unique de la vérité» et peut être utilisé pour rejouer l'état de toutes les entités simplement en itérant les événements stockés (essentiellement comme un journal des événements)
  11. La combinaison des deux (c.-à-d. Laisser les racines agrégées utiliser Event-sourcing pour externaliser la sauvegarde de leurs modifications avant de rendre compte à la Saga) offre de nombreuses possibilités intéressantes, dont l'une concerne ma question ...

Je sentais que je devais retirer cela de mon épaule, car c'est beaucoup à saisir en une seule fois. Compte tenu de ce contexte / état d'esprit (encore une fois, veuillez corriger si vous avez tort)

la question: lorsqu'une racine agrégée reçoit une action de compensation et si cette racine agrégée a externalisé ses changements d'état à l'aide de la source d'événements, l'action de compensation dans toutes les situations ne serait-elle pas simplement une suppression du dernier événement du magasin d'événements pour cela compte tenu de la racine globale? (En supposant que la mise en œuvre persistante autorise les suppressions)

Cela aurait beaucoup de sens pour moi (et serait un autre grand avantage de cette combinaison), mais comme je l'ai dit, je pourrais faire ces hypothèses sur la base d'une compréhension incorrecte / incomplète de ces concepts.

J'espère que cela n'a pas été trop long.

Merci.

Geert-Jan
la source

Réponses:

9

Vous ne devez pas supprimer les événements de votre magasin d'événements. Ceux-ci représentent quelque chose qui s'est produit. Si quelque chose se produit maintenant, vous devez également le savoir, donc ajoutez un événement qui forcera votre agrégat à revenir à un état précédent. C'est dommage de supprimer des informations de votre base de données.

pensez à l'exemple du chariot de greg young et des articles retirés. Peut-être demain, les informations sur les actions compensatoires pourraient avoir n'importe quelle valeur.

Quant à la saga, tout est correct, pour autant que je me connaisse. Vous devriez considérer la saga comme une machine d'État. Cela ne fait que cela.

C'est un commandement que la saga émet pour dire à l'agrégat de faire quelque chose. De cette action, il y aura un événement. Cet événement peut être l'action corrective dont vous avez besoin, ou peut avoir besoin d'être dénormalisé dans une vue afin que certains utilisateurs le voient pour décider quoi faire.

Cela dépend des règles de votre entreprise. Soit, il existe une solution simple: la racine agrégée sait que dans ce cas, vous le faites, ou le choix est trop complexe pour être effectué par programme (les coûts de développement sont trop élevés) et, par conséquent, vous pouvez proposer cela à un utilisateur, qui pourrait choisir entre différentes actions. Tout dépend du contexte de l'action compensatoire. Il s'agit de règles commerciales pures. Que devons-nous faire dans ce cas ou dans ce cas. C'est quelque chose à demander à votre expert de domaine, puis à choisir avec lui, s'il vaut mieux développer une solution automatique ou si la solution est de demander à l'utilisateur Ronald R., car c'est lui qui répond habituellement à cette question.

Arthis
la source
Comment l'agrégat saurait-il dans quel état revenir? Serait-il autorisé à interroger le magasin d'événements ou quelque chose?
Geert-Jan
Il ne devrait pas revenir mais ajouter un autre événement. C'est un commandement que la saga émet pour dire à l'agrégat de faire quelque chose. De cette action, il y aura un événement.
Arthis
Oui, je comprends. "Revert" était probablement mal choisi. Considérez ce qui suit: Je souhaiterais peut-être utiliser Event Sourcing avec Sagas pour la modélisation, entre autres, des flux de publication / approbation de documents. Que se passe-t-il si un éditeur a envoyé une action ChangeBlogBody qui est finalement persistée en tant qu'événement BlogBodyChanged dans le magasin d'événements. Par la suite, pour une raison quelconque, une action de compensation est émise. Comment l'agrégat pourrait-il savoir quel événement compenser à déclencher qui se traduit par le contenu du corps du blog tel qu'il était juste avant l'émission de l'action ChangeBlogBody?
Geert-Jan
Cela dépend des règles de votre entreprise. Soit, il existe une solution simple: la racine agrégée sait que dans ce cas, vous le faites, ou le choix est trop complexe pour être effectué par programme (les coûts de développement sont trop élevés) et, par conséquent, vous pouvez proposer cela à un utilisateur, qui pourrait choisir entre différentes actions.
Arthis
Tout dépend du contexte de l'action compensatoire. Il s'agit de règles commerciales pures. Que devons-nous faire dans ce cas ou dans ce cas. C'est quelque chose à demander à votre expert de domaine, puis à choisir avec lui, s'il vaut mieux développer une solution automatique ou si la solution est de demander à l'utilisateur Ronald R., car c'est lui qui répond habituellement à cette question.
Arthis
6

Pour être complet, j'ai pensé à inclure un extrait pertinent de Martin Fowler sur les moyens de revenir à l'état:

En plus des événements qui se jouent vers l'avant, il est également souvent utile pour eux de pouvoir s'inverser.

L'inversion est la plus simple lorsque l'événement est exprimé sous la forme d'une différence. Un exemple de ceci serait «ajouter 10 $ au compte de Martin» par opposition à «régler le compte de Martin à 110 $». Dans le premier cas, je peux inverser en soustrayant simplement 10 $, mais dans le dernier cas, je n'ai pas assez d'informations pour recréer la valeur passée du compte.

Si les événements d'entrée ne suivent pas l'approche de la différence, l'événement doit garantir qu'il stocke tout le nécessaire pour l'inversion pendant le traitement. Vous pouvez le faire en stockant les valeurs précédentes sur toute valeur modifiée, ou en calculant et en stockant les différences sur l'événement.

De: http://martinfowler.com/eaaDev/EventSourcing.html

Geert-Jan
la source
1

Conceptuellement:

  • L'événement est quelque chose qui s'est passé. Le passé ne peut pas être changé.
  • Le commandement est quelque chose à faire. La commande peut ne pas se produire (peut être rejetée).

Nous ne pouvons changer notre futur état qu'en exécutant une autre commande (Compenser Action) qui devrait entraîner un changement d'état des événements de l'application.

Pour "désembrouiller" la question, pensez à cette phrase "supprimer du dernier événement":

  • Que faire si le dernier événement n'est pas celui qui doit être supprimé? Que faire si d'autres événements se sont produits après celui à supprimer? Ces événements doivent également être modifiés (car leur état de base aurait changé en supprimant l'événement avant eux).
  • Que faire si l'événement a été envoyé au système externe? Vous pouvez n'avoir aucun accès pour corriger son état autre que l'envoi d'un autre événement.

En bref, vous n'avez pas la possibilité de supprimer des événements dans le modèle CQRS.

Vous pouvez réduire votre magasin d'événements en créant un état d'instantané (qui est basé sur tous les événements menant à cet état), mais cet aspect physique n'a rien à voir avec le concept d'événement.

uvsmtid
la source
0

Geert-Jan, je pense moi aussi que l'action de compensation peut simplement supprimer le ou les événements correspondants. Cela a du sens et montre un autre avantage du modèle de conception Event Sourcing: une mise en œuvre plus facile du modèle de conception de transaction de compensation.

Certains disent que la suppression de l'événement viole les «principes» de la recherche d'événements ou CQRS. Je pense que c'est une généralisation limitante. Je pense qu'il est correct de supprimer un événement s'il a été créé dans le cadre d'une transaction globale qui est annulée. Considérez le pseudocode:

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

Supposons que votre magasin d'événements soit une base de données transactionnelle. Dans le pseudocode, vous pouvez imaginer la situation où vous avez inséré le premier événement, mais lorsque vous essayez d'insérer le deuxième événement, une exception a été levée. La commande de restauration annulerait naturellement l'insertion du premier événement. Est-ce raisonnable?

S'il est raisonnable pour une transaction de base de données ACID (transaction avec commit / rollback), pourquoi ne serait-il pas raisonnable pour une transaction compensatrice?

Lors de l'exécution de la transaction Saga globale, les modifications des données peuvent être annulées (par compensation). Il n'est pas nécessaire de conserver l'événement créé lors de la transaction car la transaction ne s'est pas terminée.

Maintenant, si la compensation tente de supprimer un événement et que cet événement n'est pas le plus récent événement sur un objet, la suppression ne doit pas se produire. Mais en général, cela ne se produira probablement pas, en particulier dans les solutions à lecture intensive.

Paulo Merson
la source
0

Jouons avec l'idée que le stockage d'événements n'est que des données que vous souhaitez enregistrer. Par exemple, nous pouvons avoir un disque dur, nous pouvons commencer au début et y écrire des données. Chaque fois que nous avons un événement, nous ajoutons nos données précédentes, nous continuons donc d'écrire sur le disque où nous nous sommes arrêtés la dernière fois. Lorsque nous voulons supprimer un événement, nous revenons en arrière, supprimons cette partie du disque et laissons un espace. Revenir en arrière ralentit notre stockage d'événements, mais nous pouvons vivre avec cela. Si nous utilisons un système de fichiers, cela tentera de combler le vide avec ces derniers événements, donc nous finirons par avoir un stockage fragmenté lent ou nous pouvons faire une défragmentation. Nous n'aimons ni l'un ni l'autre. Si nous parlons de bases de données, vous obtenez ceci si vous utilisez une base de données relationnelle au lieu d'une base de données à ajouter uniquement pour stocker vos événements:

entrez la description de l'image ici réf: https://cambridge-intelligence.com/bringing-time-series-data-to-life-with-keylines/

Ofc. par un site normal, cela n'a pas d'importance, mais ces solutions sont conçues pour d'énormes sites Web tels que facebook, google, etc. vous appelez la compensation quelque chose comme construire une machine à remonter le temps et remonter dans le temps pour changer ou empêcher un événement ???

Autant que je sache. la seule façon de résoudre ce problème consiste à créer un nouveau stockage d'événements dans lequel vous excluez les événements que vous ne souhaitez pas avoir, puis à supprimer l'ancien stockage d'événements. Mais c'est une solution extrême pour supprimer un seul événement. Si nous parlons du RGPD, la seule bonne solution relative que je connaisse est de stocker des données personnelles chiffrées dans le stockage des événements et de supprimer la clé de chiffrement d'une base de données différente.

inf3rno
la source