Je travaille sur un petit exemple d'application pour apprendre les concepts du CQRS et du sourcing d'événements. J'ai un Basket
agrégat et un Product
agrégat qui devraient fonctionner indépendamment.
Voici un pseudo code pour montrer l'implémentation
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; }
Les commandes sont assez similaires aux événements, utilisant le nom impératif et non au passé.
En ce moment, cela fonctionne très bien indépendamment. J'émets une commande AddItem
, et elle crée un ItemAdded
événement sur l' Basket
ensemble qui fait ce qu'elle doit faire avec l'état du «panier». De même, pour le produit, la commande et les événements fonctionnent très bien.
Je voudrais maintenant combiner cela en un processus qui se passerait comme ceci (en termes de commandes et d'événements qui se produisent):
Le gestionnaire de processus ferait ce qui suit:
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...
Les questions auxquelles je n'ai pas pu trouver de réponses définitives sont:
- Dois-je persister le gestionnaire de processus? Il semble que ce soit le cas, mais je ne suis pas sûr
- Si je le fais, je dois enregistrer les événements pour le gestionnaire de processus. Cependant, les événements qu'il écoute sont liés aux agrégats. Dois-je ajouter l'ID de processus à ceux-ci? Ai-je des événements séparés uniquement pour le gestionnaire de processus? Comment faire cela et rester aussi SEC que possible
- Comment savoir à quel panier les
ProductReserved
événements sont destinés? Est-ce OK d'avoir unBasketId
sur ceux-là aussi, ou est-ce une fuite d'informations? - Comment puis-je garder une relation entre les événements, comment savoir qui a
ItemAdded
produit quelProductReserved
événement? Dois-je transmettre unEventId
? Cela semble étrange ... - Dois-je implémenter le en
Basket
tant que gestionnaire de processus au lieu d'un simple agrégat?
Après quelques recherches supplémentaires, je suis arrivé à ceci: Une saga est quelque chose qui garde ses propres événements et écoute les événements de l'extérieur. Fondamentalement, c'est un agrégat qui peut également réagir aux événements qui se produisent en dehors de son propre petit monde.
Un gestionnaire de processus fonctionne avec les événements de l'extérieur et envoie des commandes. Son historique peut être reconstruit à partir des événements qui se sont produits sur les agrégats qui partagent un identifiant commun comme un correlationId.
la source
Réponses:
Revoyez ce que Rinat Abdullin a écrit sur l' évolution des processus commerciaux . En particulier, notez sa recommandation de développer un processus métier dans un environnement en évolution rapide - un gestionnaire de processus est "juste" un remplacement automatisé pour un être humain qui regarde un écran.
Mon propre modèle mental de gestionnaire de processus est qu'il s'agit d'une projection provenant d'événements que vous pouvez interroger pour obtenir une liste des commandes en attente.
C'est un modèle de lecture. Vous pouvez reconstruire le gestionnaire de processus à partir de l'historique des événements chaque fois que vous en avez besoin; ou vous pouvez le traiter comme un instantané que vous mettez à jour.
Non - le gestionnaire de processus est un gestionnaire . Il ne fait rien d'utile en soi; au lieu de cela, il indique aux agrégats de faire le travail (c'est-à-dire d'apporter des modifications au livre des comptes).
Sûr. Remarque: dans la plupart des "vrais" domaines commerciaux, vous n'insisterez pas pour réserver un inventaire avant de traiter une commande; cela ajoute une contention inutile à l'entreprise. Il est plus probable que votre entreprise veuille accepter la commande, puis s'excuse dans les rares cas où la commande ne peut pas être exécutée dans le délai requis.
Les messages ont des métadonnées - en particulier, vous pouvez inclure un causationIdentifier (afin que vous puissiez identifier quelles commandes ont produit quels événements) et un correlationIdentifier , pour suivre généralement la conversation.
Par exemple, le gestionnaire de processus écrit son propre id en tant que correlationId dans la commande; les événements produits par une copie de l'ID de corrélation de la commande, et votre gestionnaire de processus s'abonne à tous les événements qui ont son propre correlationId.
Ma recommandation est non. Mais Udi Dahan a une opinion différente que vous devriez revoir; c'est que CQRS n'a de sens que si vos agrégats sont des sagas - Udi a utilisé la saga à l'endroit où le gestionnaire de processus est devenu l'orthographe dominante.
Pas vraiment? Les gestionnaires de processus sont principalement concernés par l'orchestration et non par l'état du domaine. Une instance d'un processus aura un "état", sous la forme d'un historique de tous les événements qu'ils ont observés - la bonne chose à faire en réponse à l'événement Z dépend de la présence ou non d'événements X et Y Ainsi, vous devrez peut-être être en mesure de stocker et de charger une représentation de cet état (qui pourrait être quelque chose de plat, ou pourrait être l'historique des événements observés).
(Je dis «pas vraiment» parce que l' agrégat est défini de manière assez vague pour qu'il ne soit pas complètement faux de prétendre que la liste des événements observés est un «agrégat». Les différences sont plus sémantiques que l'implémentation - nous chargeons l' état du processus et décidons ensuite à quels messages envoyer aux parties du système responsables de l' état du domaine . Il y a un peu de main qui se passe ici.)
Pas tout à fait - la gestion de l'État n'est pas un do-er, c'est un traqueur de garde. Dans les circonstances où le gestionnaire de processus ne doit émettre aucun signal, vous lui donnez des connexions inertes avec le monde. En d'autres termes,
dispatch(command)
c'est un no-op.la source
Ce que vous recherchez a un modèle appelé "Saga", qui est essentiellement un gestionnaire de processus.
Les saga sont également parfaites pour les processus de longue durée, car elles peuvent maintenir l'état entre les commandes corrélées.
Voici un excellent article sur les Sagas
la source