DDD, Saga i pozyskiwanie wydarzeń: czy akcja kompensacyjna może po prostu zostać usunięta z magazynu wydarzeń?


15

Zdaję sobie sprawę, że powyższe pytanie prawdopodobnie rodzi kilka „co?”, Ale spróbuję wyjaśnić:

Próbuję oprzeć głowę na kilku pokrewnych koncepcjach, w zasadzie wzorcu Saga ( http://www.rgoarchitects.com/Files/SOAPatterns/Saga.pdf ) w połączeniu z Event-Sourcing (koncepcja DDD) : http://en.wikipedia.org/wiki/Domain-driven_design )

Dobry post, który go otacza: https://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-ii-of-ii/

Przechodzę do pytania za minutę, ale myślę, że najpierw muszę spróbować streścić to, co rozumiem (co może być nie tak, więc proszę popraw, jeśli tak jest), ponieważ może to mieć wpływ na to, dlaczego jestem zadając pytanie na początek:

  1. Wzorzec Saga jest rodzajem brokera, który wydał akcję (użytkownik końcowy, zautomatyzowany itp. Zasadniczo wszystko, co ma zmienić dane) dzieli tę akcję na działania biznesowe i wysyła każde z tych działań jako wiadomości do szyny komunikatów, która z kolei wysyła je do odpowiednich zagregowanych korzeni, którymi należy się zająć.
  2. Te zagregowane korzenie mogą działać całkowicie autonomicznie (ładne rozdzielenie problemów, świetna skalowalność itp.)
  3. Sama instancja Saga nie zawiera żadnej logiki biznesowej, która jest zawarta w zagregowanych korzeniach, do których wysyła działania. Jedyną „logiką” zawartą w Sadze jest logika „procesowa” (często implementowana jako Statemachine), która określa na podstawie otrzymanych działań (a także zdarzeń kontrolnych), co robić (tj. Jakie działania wysłać)
  4. Wzory Saga implementują rodzaj rozproszonego wzorca transakcji. Tj .: gdy jeden z zagregowanych korzeni (które znów działają autonomicznie, nie wiedząc o istnieniu siebie nawzajem) zawiedzie, cała akcja może wymagać wycofania.
  5. Jest to realizowane przez posiadanie wszystkich zagregowanych korzeni, po zakończeniu ich sprawozdania z działalności z powrotem do Sagi. (W przypadku sukcesu, jak i błędu)
  6. W przypadku, gdy wszystkie zagregowane korzenie zwrócą sukces, wewnętrzny statemachine, jeśli Saga określa, co dalej (lub zdecyduje, że to zrobione)
  7. W przypadku niepowodzenia Saga przekazuje wszystkim zagregowanym korzeniom, które brały udział w ostatnim działaniu, tak zwane Akcje kompensacyjne, tj .: działanie mające na celu cofnięcie ostatniego działania każdego z zagregowanych korzeni.
  8. Może to być po prostu „głosowanie minus 1”, jeśli akcja brzmiała „plus głos”, ale może to być bardziej skomplikowane, jak przywrócenie posta na blogu do jego poprzedniej wersji.
  9. Pozyskiwanie zdarzeń (patrz łączący oba posty na blogu) ma na celu zewnętrzne zapisanie wyników każdego działania, które każde z zagregowanych źródeł podejmuje w scentralizowanym magazynie zdarzeń (w tym kontekście zmiany nazywane są „zdarzeniami”)
  10. Ten magazyn zdarzeń jest „pojedynczą wersją prawdy” i można go użyć do odtworzenia stanu wszystkich bytów po prostu poprzez iterację przechowywanych zdarzeń (zasadniczo jak dziennik zdarzeń)
  11. Połączenie tych dwóch (tj. Zezwolenie na łączenie korzeni z wykorzystaniem Event-sourcingu w celu outsourcingu zapisywania ich zmian przed zgłoszeniem się do Sagi) daje wiele fajnych możliwości, z których jedna dotyczy mojego pytania ...

Czułem, że muszę to zdjąć z ramienia, ponieważ za jednym razem trzeba to dużo uchwycić. Biorąc pod uwagę ten kontekst / sposób myślenia (ponownie, proszę poprawić, jeśli jest źle)

pytanie: kiedy zagregowany root otrzyma akcję kompensacji i jeśli ten agregat root zlecił outsourcing zmian stanu za pomocą pozyskiwania zdarzeń, czy akcja kompensacji we wszystkich sytuacjach nie byłaby po prostu usunięciem ostatniego zdarzenia w magazynie zdarzeń biorąc pod uwagę Root Aggregate? (Zakładając, że implementacja trwała umożliwia usuwanie)

Miałoby to dla mnie wiele sensu (i byłaby kolejną wielką zaletą tej kombinacji), ale jak powiedziałem, mogę przyjmować te założenia w oparciu o niepoprawne / niepełne zrozumienie tych pojęć.

Mam nadzieję, że nie rozwinęło się to zbyt długo.

Dzięki.

Odpowiedzi:


9

Nie należy usuwać wydarzeń ze sklepu z wydarzeniami. Reprezentują one coś, co się wydarzyło. Jeśli coś się stanie teraz, powinieneś to również wiedzieć, dlatego dodaj zdarzenie, które zmusi agregat do powrotu do poprzedniego stanu. Szkoda usunąć informacje z bazy danych.

pomyśl o przykładzie koszyka Grega Younga i usuniętych przedmiotach. Może być jutro informacja o działaniach kompensacyjnych może mieć jakąkolwiek wartość.

Jeśli chodzi o sagę, wszystko jest prawidłowe, o ile wiem. Powinieneś pomyśleć o sadze jak o maszynie państwowej. Robi tylko to.

Jest to rozkaz wydany przez sagę, aby poinformować grupę, by coś zrobiła. Z tej akcji będzie wydarzenie. To zdarzenie może być działaniem naprawczym, którego potrzebujesz, lub może wymagać denormalizacji w widoku, aby jakiś użytkownik zobaczył to, aby zdecydować, co zrobić.

To zależy od twoich reguł biznesowych. Albo istnieje łatwa poprawka: zagregowany root wie, że w takim przypadku robisz to, lub wybór jest zbyt skomplikowany, aby można go było wykonać programowo (koszty rozwoju są zbyt wysokie), dlatego możesz zaproponować to użytkownikowi, który może wybierać między różnymi działaniami. Wszystko zależy od kontekstu akcji kompensacyjnej. To są czyste zasady biznesowe. Co powinniśmy zrobić w tej sprawie lub w tej sprawie. To jest pytanie, które należy zadać ekspertowi w dziedzinie, a następnie wybrać z nim, czy lepiej jest opracować automatyczne rozwiązanie, czy też rozwiązaniem jest zapytanie użytkownika Ronalda R., ponieważ to on zazwyczaj odpowiada na to pytanie.


Skąd agregat wiedziałby, do którego stanu należy przywrócić? Czy można zapytać o sklep z wydarzeniami czy coś takiego?
Geert-Jan

Nie powinno się cofać, ale należy dodać kolejne wydarzenie. Jest to rozkaz wydany przez sagę, aby poinformować grupę, by coś zrobiła. Z tej akcji będzie wydarzenie.
Arthis,

Tak, rozumiem. „Revert” został prawdopodobnie źle wybrany. Rozważ następujące kwestie: może chciałbym użyć Sourcingu zdarzeń w Sagas do modelowania, między innymi, przepływów publikacji / zatwierdzania dokumentów. Co się stanie, jeśli redaktor wyśle ​​działanie ChangeBlogBody, które jest ostatecznie utrwalane jako zdarzenie BlogBodyChanged do Event Store. Następnie z jakiegoś powodu wydawane jest działanie kompensacyjne. Skąd agregat wiedziałby, jakie zdarzenie kompensacyjne do uruchomienia, które powoduje zawartość treści bloga, tak jak było tuż przed wydaniem akcji ChangeBlogBody?
Geert-Jan

To zależy od twoich reguł biznesowych. Albo istnieje łatwa poprawka: zagregowany root wie, że w takim przypadku robisz to, lub wybór jest zbyt skomplikowany, aby można go było wykonać programowo (koszty rozwoju są zbyt wysokie), dlatego możesz zaproponować to użytkownikowi, który może wybierać między różnymi działaniami.
Arthis,

Wszystko zależy od kontekstu akcji kompensacyjnej. To są czyste zasady biznesowe. Co powinniśmy zrobić w tej sprawie lub w tej sprawie. To jest pytanie, które należy zadać ekspertowi w dziedzinie, a następnie wybrać z nim, czy lepiej jest opracować automatyczne rozwiązanie, czy też rozwiązaniem jest zapytanie użytkownika Ronalda R., ponieważ to on zazwyczaj odpowiada na to pytanie.
Arthis,

6

Dla kompletności pomyślałem o dołączeniu odpowiedniego fragmentu Martina Fowlera o sposobach przywrócenia stanu:

Oprócz wydarzeń rozgrywających się do przodu, często przydaje im się również możliwość cofnięcia się.

Odwrócenie jest najłatwiejsze, gdy wydarzenie zostanie rzucone w formie różnicy. Przykładem tego może być „dodanie 10 $ do konta Martina”, a nie „ustawienie konta Martina na 110 $”. W pierwszym przypadku mogę cofnąć, odejmując 10 USD, ale w drugim przypadku nie mam wystarczających informacji, aby odtworzyć przeszłą wartość konta.

Jeśli zdarzenia wejściowe nie są zgodne z podejściem różnicy, zdarzenie powinno zapewnić, że przechowuje wszystko, co jest potrzebne do cofnięcia podczas przetwarzania. Można to zrobić, przechowując poprzednie wartości dowolnej wartości, która została zmieniona, lub obliczając i przechowując różnice w zdarzeniu.

Od: http://martinfowler.com/eaaDev/EventSourcing.html


1

Koncepcyjnie:

  • Wydarzenie jest czymś, co się stało. Przeszłości nie można zmienić.
  • Dowodzenie jest czymś do zrobienia. Polecenie może się nie wydarzyć (może zostać odrzucone).

Możemy zmienić nasz przyszły stan tylko poprzez wykonanie innego polecenia (Kompensacja), co powinno spowodować zmianę stanu zdarzeń przez aplikację.

Aby „dezorientować” pytanie, pomyśl o tym frazie „usuń ostatnie zdarzenie”:

  • Co jeśli ostatnie zdarzenie nie jest tym, które należy usunąć? Co jeśli inne zdarzenia miały miejsce po tym, który ma zostać usunięty? Te zdarzenia również muszą zostać zmienione (ponieważ ich stan podstawowy zmieniłby się poprzez usunięcie zdarzenia przed nimi).
  • Co jeśli zdarzenie zostało wysłane do systemu zewnętrznego? Możesz nie mieć dostępu do korygowania stanu innego niż wysłanie innego zdarzenia.

Krótko mówiąc, nie masz opcji usuwania zdarzeń w ramach wzorca CQRS.

Możesz zmniejszyć swój magazyn zdarzeń, tworząc stan migawki (który jest oparty na wszystkich zdarzeniach prowadzących do tego stanu), ale ten aspekt fizyczny nie ma nic wspólnego z pojęciem zdarzenia.


0

Geert-Jan, również uważam, że akcja kompensacyjna może po prostu usunąć odpowiednie zdarzenie (zdarzenia). Ma to sens i pokazuje kolejną zaletę wzorca projektowego Sourcing Event: łatwiejsze wdrożenie wzorca projektowego Transakcji kompensacyjnej.

Niektórzy twierdzą, że usunięcie wydarzenia narusza „zasady” pozyskiwania zdarzeń lub CQRS. Myślę, że jest to ograniczenie uogólniające. Myślę, że można usunąć zdarzenie, jeśli zostało utworzone w ramach anulowanej transakcji globalnej. Rozważ pseudokod:

try {
    newEvents = processMycommand(myCommand)
    for (Event newEvent : newEvents)
        EventStore.insertEvent(newEvent);
} catch (Exception e) {
    EventStore.rollback();
}

Załóżmy, że Twój magazyn zdarzeń jest transakcyjną bazą danych. W pseudokodzie można wyobrazić sobie sytuację, w której wstawiono pierwsze zdarzenie, ale podczas próby wstawienia drugiego zdarzenia został zgłoszony wyjątek. Polecenie wycofania naturalnie cofnęłoby wstawienie pierwszego zdarzenia. Czy to rozsądne?

Jeśli jest to uzasadnione dla transakcji bazy danych ACID (transakcja z zatwierdzeniem / wycofaniem), dlaczego nie byłoby uzasadnione dla transakcji kompensującej?

Podczas realizacji globalnej transakcji Saga zmiany danych można cofnąć (za wynagrodzeniem). Nie ma potrzeby zatrzymywania zdarzenia utworzonego podczas transakcji, ponieważ transakcja nie została zakończona.

Teraz, jeśli kompensacja próbuje usunąć zdarzenie, a to zdarzenie nie jest najnowszym zdarzeniem na obiekcie, usunięcie nie powinno nastąpić. Ale ogólnie rzecz biorąc, jest to mało prawdopodobne, szczególnie w przypadku rozwiązań wymagających intensywnego odczytu.


0

Zagrajmy z myślą, że przechowywanie zdarzeń to tylko dane, które chcesz zapisać. Na przykład możemy mieć dysk twardy, możemy zacząć od początku i zapisywać na nim dane. Za każdym razem, gdy mamy zdarzenie, dołączamy nasze poprzednie dane, więc po prostu kontynuujemy zapisywanie na dysku, na którym ostatnio się zatrzymaliśmy. Kiedy chcemy usunąć zdarzenie, cofamy się, usuwamy tę część z dysku i pozostawiamy lukę. Cofanie się samoistnie spowalnia magazynowanie wydarzeń, ale możemy z tym żyć. Jeśli użyjemy systemu plików, który spróbuje wypełnić lukę późniejszymi zdarzeniami, w rezultacie będziemy mieć powolne pofragmentowane miejsce do przechowywania danych lub możemy przeprowadzić defragmentację. Żadne z nich nie jest czymś, co lubimy. Jeśli mówimy o bazach danych, otrzymujesz to, jeśli do przechowywania zdarzeń używasz relacyjnej bazy danych zamiast tylko bazy danych dołączającej:

wprowadź opis zdjęcia tutaj ref: https://cambridge-intelligence.com/bringing-time-series-data-to-life-with-keylines/

Ofc. w przypadku zwykłej witryny nie ma to znaczenia, ale te rozwiązania są przeznaczone dla dużych witryn, takich jak Facebook, Google itp. Tak naprawdę pytanie nie ma sensu, ponieważ jak usunąć zdarzenie w bazie danych dołączającej i jak nazywasz odszkodowanie czymś w rodzaju budowy wehikułu czasu i cofania się w czasie, aby zmienić lub zapobiec zdarzeniu?

Afaik. jedynym sposobem na rozwiązanie tego jest utworzenie nowego magazynu zdarzeń, w którym wykluczone zostaną zdarzenia, których nie chcesz mieć, a następnie usunięcie starego magazynu zdarzeń. Ale to ekstremalne rozwiązanie, aby usunąć pojedyncze zdarzenie. Jeśli mówimy o RODO, to jedynym relatywnie dobrym rozwiązaniem, jakie znam, jest przechowywanie danych osobowych zaszyfrowanych w pamięci zdarzeń i usuwanie klucza szyfrowania z innej bazy danych.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.