Ich arbeite an einer kleinen Beispielanwendung, um die Konzepte von CQRS und Event-Sourcing zu erlernen. Ich habe ein Basket
Aggregat und ein Product
Aggregat, die unabhängig voneinander arbeiten sollten.
Hier ist ein Pseudocode zur Veranschaulichung der Implementierung
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; }
Befehle sind den Ereignissen ziemlich ähnlich und verwenden den imperativen Namen und nicht die Vergangenheitsform.
Im Moment funktionieren diese unabhängig voneinander einwandfrei. Ich gebe einen Befehl aus AddItem
und es wird ein ItemAdded
Ereignis auf dem Basket
Aggregat erstellt, das das tut, was es mit dem Status des 'Basket' zu tun hat. In ähnlicher Weise funktionieren der Befehl und die Ereignisse für das Produkt einwandfrei.
Ich möchte dies jetzt zu einem Prozess kombinieren, der ungefähr so ablaufen würde (in Bezug auf Befehle und Ereignisse, die passieren):
Der Prozessmanager würde Folgendes tun:
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...
Die Fragen, auf die ich keine endgültigen Antworten finden konnte, sind:
- Muss ich den Prozessmanager beibehalten? Es scheint so, als ob ich es tue, aber ich bin mir nicht sicher
- In diesem Fall muss ich die Ereignisse für den Prozessmanager speichern. Die Ereignisse, die abgehört werden, sind jedoch an die Aggregate gebunden. Füge ich diesen die Prozess-ID hinzu? Habe ich separate Ereignisse nur für den Prozessmanager? Wie man das macht und so trocken wie möglich hält
- Woher weiß ich, für welchen Warenkorb die
ProductReserved
Veranstaltungen sind? Ist es in Ordnung, eineBasketId
zu haben, oder sind das undichte Informationen? - Wie halte ich eine Beziehung zwischen Ereignissen, woher weiß ich,
ItemAdded
welchesProductReserved
Ereignis welches hervorgebracht hat ? Gebe ich einEventId
? Das scheint seltsam ... - Sollte ich das
Basket
als Prozessmanager anstelle eines einfachen Aggregats implementieren ?
Nach einigen weiteren Nachforschungen bin ich zu folgendem gekommen: Eine Saga ist etwas, das seine eigenen Ereignisse beibehält und Ereignisse von außen abhört. Grundsätzlich ist es ein Aggregat, das auch auf Ereignisse außerhalb seiner eigenen kleinen Welt reagieren kann.
Ein Prozessmanager arbeitet mit den Ereignissen von außen und sendet Befehle aus. Der Verlauf kann anhand der Ereignisse auf den Aggregaten wiederhergestellt werden, die einen gemeinsamen Bezeichner wie eine Korrelations-ID haben.