Pracuję nad małą przykładową aplikacją do nauki pojęć CQRS i pozyskiwania zdarzeń. Mam Basket
agregat i Product
agregat, który powinien działać niezależnie.
Oto pseudo kod pokazujący implementację
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; }
Polecenia są bardzo podobne do zdarzeń, używają nazwy rozkazującej, a nie czasu przeszłego.
W tej chwili działają one samodzielnie niezależnie. Wydaję polecenie AddItem
, a ono tworzy ItemAdded
zdarzenie w Basket
agregacie, które robi to, co musi zrobić ze stanem „Koszyka”. Podobnie w przypadku produktu polecenia i zdarzenia działają dobrze.
Chciałbym teraz połączyć to w proces, który przebiegałby mniej więcej tak (pod względem poleceń i zdarzeń, które się zdarzają):
Kierownik procesu wykonałby następujące czynności:
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...
Pytania, na które nie mogłem znaleźć ostatecznych odpowiedzi, to:
- Czy muszę utrwalać menedżera procesów? Wygląda na to, że tak, ale nie jestem pewien
- Jeśli tak, muszę zapisać zdarzenia dla menedżera procesów. Jednak zdarzenia, których słucha, są powiązane z agregacjami. Czy dodam do nich identyfikator procesu? Czy mam osobne zdarzenia tylko dla menedżera procesu? Jak to zrobić i zachować jak największą SUSZENIE
- Skąd mam wiedzieć, dla którego koszyka
ProductReserved
są wydarzenia? Czy to jest w porządku miećBasketId
je też, czy to przeciekające informacje? - Jak zachować związek między wydarzeniami, skąd mam wiedzieć, które
ItemAdded
wydało któreProductReserved
wydarzenie? Czy przekazujęEventId
? To wydaje się dziwne ... - Czy powinienem implementować
Basket
jako menedżer procesów zamiast zwykłego agregatu?
Po kilku dalszych badaniach doszedłem do tego: Saga jest czymś, co utrzymuje własne wydarzenia i słucha wydarzeń z zewnątrz. Zasadniczo jest to agregat, który może również reagować na zdarzenia zachodzące poza jego własnym małym światem.
Menedżer procesów współpracuje ze zdarzeniami z zewnątrz i wysyła polecenia. Jego historię można odbudować na podstawie zdarzeń, które miały miejsce w agregatach, które mają wspólny identyfikator, taki jak korelacja.