Mikroserwisy: rodzaje zdarzeń

2021-06-01

Termin zdarzenie ma w programowaniu wiele znaczeń. Kiedyś mógł być kojarzony głównie z UI - wydarzenia (eventy ;) ) dotyczyły interakcji użytkownikiem, np. kliknięcia przeń w dany przycisk. W świecie mikroserwisów, DDD itp. - to znaczenie jednak się zmieniło (a może rozszerzyło). Dziś tych zakresów znaczeniowych jest więcej, mogą się one mieszać i nie zawsze wiadomo, o jaki rodzaj eventu chodzi. Na przykładzie projektu, w którym pracowałem, a który był oparty o “referencyjną” architekturę eShopOnConatiners (czyli Microsoftowego przykładu rozwiązania mikroserwisowo-kontenerowego) - będę chciał pokazać typologię różnych znaczeń terminu zdarzenie.

Zdarzenie w ramach encji

Gdy stosujemy event sourcing, to w zasadzie wszelkie zmiany stanu domeny dzieją się za pomocą zdarzeń. Gdy zamówienie zostało złożone (OrderWasCreated), gdy zamówienie zostało opłacone (OrderWasPaid), gdy zamówienie zostało anulowane (OrderWasCancelled) i tak dalej. Te wydarzenia w zasadzie mapują się na wydarzenia, które możemy rozpoznać podczas sesji event stormingu. One też są zapisywane w event store. O ile dobrze przejrzałem projekt eShopOnContainers, nie ma tam takich zdarzeń, jednak spotkałem się z takim rozwiązaniem właśnie w przypadku serwisu implementującego event sourcing.

Zdarzenia domenowe

Jeśli stosujemy event sourcing, być może to rozróżnienia na zdarzenia “wewnątrz encji” i “domenowe” wydaje się bez sensu, ale w przypadku modelowania DDD, ale bez event sourcingu, nie będziemy mieć tych pierwszych, ale te drugie - już tak. Otóż, gdy zachodzi potrzeba reakcji jednego agregatu na zmianę w drugim agregacie - wówczas możemy posłużyć się takim zdarzeniem domenowym. W tym przykładowym repozytorium eShopOnConatiners reprezentowane są one przez klasy z sufiksem -DomainEvent. Ich rolą jest “komunikacja” pomiędzy agregatami. Być może słowo “komunikacja” nie jest precyzyjne, gdyż mamy tu do czynienia raczej ze schematem producent oraz potencjalnie wielu konsumentów. Kiedy takie zdarzenie może być potrzebne? Jak wiadomo, agregaty nie mają możliwości wprost wywoływania swoich metod - byłyby wówczas ze sobą powiązane. Jeśli mamy np. skompilkowaną strukturę zarządzania magazynu, gdzie dostawa wymaga obsługi zarówno przez agregat Warehouse (np. ulokowanie paczki w odpowiednim miejscu fizycznego magazynu), ale też poinformowania agregatu StockProduct o zwiększeniu ilości stanu magazynowego - wówczas z agregatu Warehouse możemy wywołać wydarzenie ProductReceived, który będzie obsłużony przez inny agregat. W praktyce przykładu eShopOnContainers wygląda to tak, że każdy agregar zawiera kolekcję “wydarzeń do opublikowania”, które jest “opróżniana” podczas zapisywania encji. Opróżnianie polega zaś na wysłaniu tych wydarzeń do mediatora, co z kolei wymaga napisania handlera dla takiego wydarzenia, w którym możemy zawołać metodę z innego agregatu. W efekcie uzyskujemy też to, że cała operacja jest wykonywana w transakcji (a przynajmniej może być) - ma to swój plus, gdyż nie ma możliwości, żeby takie wydarzenie gdzieś utknęło (dostawa dotarła do magazynu, ale nie został zwiększony stan magazynowy), ale z drugiej strony - błędy w handlerach powodują, że nie można wykonać “pierwotnej” operacji (z powodu wyjątku).

Zdarzenia integracyjne

eShopOnContainers operuje też trzecim typem wydarzeń - patrz klasy z sufiksem -IntegrationEvents. To są zdarzenia, które służą do poinformowania innych mikroserwisów o - nomen omen - wydarzeniach w ramach pojedynczego serwisu. Przykładowo, gdy użytkownik został oznaczony jako “oszust”, serwis Users powinien poinformować o tym inne serwisy: na przykład serwis Orders może anulować wszystkie jego zamówienia i wstrzymać wysyłkę produktów. W tym przykładowy repo jest to realizowane za pomocą Service Bus: serwisy “wrzucają” wydarzenia integracyjne na odpowiednie “tematy” na szynie, natomiast inne serwisy, zainteresowane danymi wydarzeniami, zawczasu subskrybują się na nie i zapewniają swój kod do obsługi takiego wydarzenia.


Robert Skarżycki - zdjęcie profilowe

Pisanina, której autorem jest Robert Skarżycki - programista .NET, mąż szczęśliwej żony, rodzic
moje bio
mój Twitter
mój LinkedIn
moje szkolenia i warsztaty

© 2022, Built with Gatsby & passion