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.
źródło
Odpowiedzi:
Przeczytaj, co napisał Rinat Abdullin na temat ewoluującego procesu biznesowego . W szczególności zwróć uwagę na jego zalecenie dotyczące opracowania procesu biznesowego w szybko zmieniającym się środowisku - kierownik procesu jest „tylko” zautomatyzowanym zamiennikiem człowieka wpatrującego się w ekran.
Mój własny model mentalny menedżera procesów polega na tym, że jest to projekcja pochodząca od zdarzenia, w której można wyszukać listę oczekujących poleceń.
To model do czytania. Menedżera procesów można odbudować z historii zdarzeń za każdym razem, gdy jest to potrzebne; lub możesz potraktować to jak aktualizowaną migawkę.
Nie - kierownik procesu jest menedżerem . Sam w sobie nie robi nic pożytecznego; zamiast tego nakazuje agregatom wykonanie pracy (tj. dokonanie zmian w księdze rekordów).
Pewnie. Uwaga: w większości „prawdziwych” domen zakupowych nie nalegasz na rezerwowanie zapasów przed przetworzeniem zamówienia; dodaje niepotrzebnej rywalizacji do firmy. Bardziej prawdopodobne jest, że Twoja firma będzie chciała przyjąć zamówienie, a następnie przeprasza w rzadkim przypadku, że zamówienie nie może zostać zrealizowane w wymaganym czasie.
Wiadomości zawierają metadane - w szczególności można dołączyć identyfikator przyczynowości (aby można było określić, które polecenia wywołały które zdarzenia) i identyfikator korelacji , aby ogólnie śledzić konwersację.
Na przykład menedżer procesów zapisuje własny identyfikator jako korelację w poleceniu; zdarzenia wygenerowane przez skopiowanie identyfikatora korelacji polecenia, a menedżer procesu subskrybuje wszystkie zdarzenia, które mają własną korelację.
Moja rekomendacja to nie. Ale Udi Dahan ma inną opinię, którą powinieneś przeanalizować; to znaczy, że CQRS ma sens tylko wtedy, gdy twoje agregaty są sagami - Udi użył sagi w miejscu, w którym kierownik procesu stał się dominującą pisownią.
Nie całkiem? Menedżerowie procesów zajmują się głównie aranżacją, a nie stanem domeny. Instancja procesu będzie miała „stan” w postaci historii wszystkich zaobserwowanych zdarzeń - właściwa czynność w odpowiedzi na zdarzenie Z zależy od tego, czy widzieliśmy zdarzenia X i Y Może więc być konieczne przechowywanie i ładowanie reprezentacji tego stanu (może to być coś płaskiego lub historia obserwowanych zdarzeń).
(Mówię „nie bardzo”, ponieważ agregacja jest zdefiniowana na tyle niejasno, że nie jest całkowicie błędem twierdzenie, że lista zaobserwowanych zdarzeń jest „agregacją”. Różnice są bardziej semantyczne niż implementacja - ładujemy stan procesu, a następnie decydujemy, do jakich komunikatów wyślij do części systemu odpowiedzialnych za stan domeny . Trwa tutaj machanie ręką).
Niezupełnie - zarządzanie stanem nie jest do zrobienia, to narzędzie do śledzenia opiekunów. W okolicznościach, gdy menedżer procesów nie powinien emitować żadnych sygnałów, dajesz mu obojętne połączenia ze światem. Innymi słowy,
dispatch(command)
jest to brak op.źródło
To, czego szukasz, ma wzorzec zwany „Saga”, który jest w zasadzie menedżerem procesów.
Sagi są również idealne do długotrwałych procesów, ponieważ mogą utrzymywać stan między skorelowanymi poleceniami.
Oto świetny artykuł na temat Sagas
źródło