Pozyskiwanie zdarzeń CQRS +: (czy to prawda, że) Polecenia są zazwyczaj przekazywane punkt-punkt, podczas gdy zdarzenia domeny są przekazywane przez pub / sub?

12

Zasadniczo próbuję owinąć głowę koncepcją CQRS i powiązanymi koncepcjami.

Chociaż CQRS niekoniecznie obejmuje przesyłanie wiadomości i pozyskiwanie zdarzeń, wydaje się być dobrą kombinacją (co można zobaczyć w wielu przykładach / postach na blogu łączących te pojęcia)

Biorąc pod uwagę przypadek użycia dla zmiany stanu czegoś (powiedzmy, aby zaktualizować Pytanie na temat SO), czy uważasz, że następujący przepływ jest poprawny (jak w najlepszej praktyce)?

System wydaje zagregowaną komendę UpdateQuestionCommand, która może być podzielona na kilka mniejszych poleceń: UpdateQuestion, która jest skierowana na Root Aggregate Root, i UpdateUserAction (zliczanie punktów itp.) Na Root Aggregate użytkownika. Są one wysyłane asynchronicznie przy użyciu wiadomości typu punkt-punkt.

Zagregowane korzenie robią swoje, a jeśli wszystko pójdzie dobrze, odpalają odpowiednio odpowiednio EventUpdated i UserActionUpdated, które zawierają stan zlecony do sklepu z wydarzeniami. Aby zachować je w Yadayada, żeby być kompletnym, nie o to tutaj chodzi.

Te zdarzenia są również umieszczane w kolejce pub / sub do emisji. Każdy subskrybent (w tym prawdopodobnie jeden lub kilka Projektorów tworzących Widoki odczytu) może subskrybować te wydarzenia.

Ogólne pytanie: czy rzeczywiście najlepszą praktyką jest, aby polecenia były przekazywane punkt-punkt (tj .: odbiornik jest znany), podczas gdy zdarzenia są nadawane (tj. Odbiornik (odbiorcy) są nieznani)?

Zakładając powyższe, jaka byłaby zaleta / wada umożliwienia nadawania Komend za pośrednictwem pub / sub zamiast punkt-punkt?

Na przykład: Podczas nadawania poleceń podczas korzystania z Sagi może być problem, ponieważ rola mediacji, jaką Saga musi odgrywać w przypadku awarii jednego z zagregowanych korzeni, jest utrudniona, ponieważ saga nie wie, które zagregowane korzenie uczestniczą na początku .

Z drugiej strony widzę zalety (elastyczność), gdy wydawanie poleceń byłoby dozwolone.

Geert-Jan
źródło
Dobrze napisane pytanie btw.
Dav

Odpowiedzi:

19

Oświadczenie: Stawiam tylko pierwsze kroki w świecie CQRS, ale mogę zaoferować moje bieżące zrozumienie sprawy i zobaczymy, czy inni to potwierdzą. Wszystko, co piszę poniżej, ma motyw przewodni „jak widzę” i nie jest autorytatywne.

Przypadek 80%

Aby odpowiedzieć na twoje pytanie, polecenia są w rzeczy samej relacją punkt-punkt. Gdy polecenie wchodzi do kontrolera (aplikacji internetowej MVC), kontroler ten następnie prosi dyspozytora poleceń o znalezienie jednego i tylko jednego odpowiedniego modułu obsługi poleceń i deleguje pracę do tego modułu obsługi.

Dlaczego nie opublikować?

To kwestia odpowiedzialności . Jeśli coś wysyła polecenie, wiąże się ono z oczekiwaniem , że się spełni. Jeśli po prostu opublikujesz i masz nadzieję, że coś gdzieś to podejmie i zacznie działać , nie ma gwarancji, że tak się stanie. Poprzez ekstrapolację nie wiesz również, czy wielu procedur obsługi nie decyduje się na wykonanie polecenia, co może skutkować wielokrotnym zastosowaniem tej samej zmiany.

Z drugiej strony wydarzenia mają charakter informacyjny i uzasadnione jest oczekiwanie, że zero, dwa lub więcej elementów będzie zainteresowanych konkretnym wydarzeniem. Naprawdę nie dbamy o to, aby wprowadzić żądaną zmianę.

Przykład

Można to porównać do prawdziwego życia. Jeśli masz troje dzieci, wejdź do pokoju i po prostu wykrzycz „Posprzątaj łazienkę”, nie masz gwarancji, że ktoś to zrobi, i nieszczęśliwie, jeśli nie zrobi się tego dwukrotnie (jeśli masz posłuszne dzieci ;-) Powinieneś lepiej, jeśli przydzielisz określone dziecko do robienia tego, co chcesz.

Kiedy to dziecko kończy pracę, wygodnie jest krzyczeć „łazienka została wyczyszczona”, aby każdy, kto chce umyć zęby, wie, że może to zrobić.

Dav
źródło
ma sens. Doskonała analogia :)
Geert-Jan
Zgubiłeś mnie w ... When a command enters a controller (MVC webapp)-? Czy korzystasz z usługi RESTful? lub niektóre hybrydowe punkty końcowe API? Czy możesz podać przykład
Piotr Kula,
@pumkin użyliśmy punktu końcowego WebAPI, który byłby wywoływany przez naszą aplikację internetową za każdym razem, gdy trzeba było wykonać polecenie. Na przykład. jeśli użytkownik chciałby dodać komentarz do wpisu, aplikacja internetowa wysłałaby żądanie POST na adres example.com/api/Post/AddPostComment.
Dav,
1

Zgadzam się, że system inicjujący ogólnie nie spodziewałby się, że polecenie zostanie zrealizowane przez wiele systemów docelowych:

  • Polecenia zwykle nigdy nie wysyłają i modlą się - system inicjujący polecenie generalnie potrzebuje asynchronicznej informacji zwrotnej w miarę postępu i rezultatu polecenia (np. Zdarzenia stanu takie jak acknowledgementi zakończone powodzeniem completionlub failuremogą zostać opublikowane przez docelowy system w celu poinformowania inicjującego system).
  • Gdyby w grę wchodziło wiele systemów docelowych, system inicjujący otrzymałby wiele (być może sprzecznych) wyników dla polecenia (np. Cel 1 osiągnął sukces, ale cel 2 nie powiódł się). Wymagałoby to dodatkowej złożoności przy określaniu rzeczywistego stanu pierwotnego polecenia (np. Czy transakcja polecenia byłaby uważana za udaną tylko wtedy, gdy wszystkie cele się powiodły? Czy polecenie musiałoby zostać wycofane lub skompensowane w udanych celach, jeśli jeden z celów nie powiódł się? itp.). Wprowadziłoby to niepożądane sprzężenie i złożoność między systemami inicjującym i docelowym.

Jednak nadal warto zasubskrybować dodatkowych (nietransakcyjnych i zwykle „rozwiązłych”) konsumentów, którzy „podsłuchują” polecenia wydawane między systemami

  • Cele kontrolne
  • Oprzyrządowanie i wskaźniki operacyjne (np. Obciążenie, analityka biznesowa itp.)
  • Złożone przetwarzanie zdarzeń lub „podsłuchiwacze” przetwarzania zdarzeń strumieniowych - systemy te mogą wykrywać błędy lub nieprawidłowości w poleceniach (np. Częstotliwość poleceń lub korelację między różnymi kombinacjami poleceń i zdarzeń) i mogą wyzwalać alarmy lub działania naprawcze (często w forma dalszych, różnych rodzajów poleceń).
StuartLC
źródło