Kontrola kolejności eventów. Co jeżeli zamkniecie zamówienia dojdzie przed otworzeniem?

1

Wejście:
Mamy mozliwy strumien eventow, ktorego skladowymi jest OrderCreated, OrderCancelled
Działanie i problem
Klient robi zamowienie a pozniej szybko kasuje.
Wiadomo, ze OrderCreated musi byc przed OrderCancelled Ktos wysle te 2 komunikaty praktycznie naraz, jeżeli OrderCancelled dojdzie pierwsze to pojdzie na straty, my nie chcemy stracić tego eventu a je ułożyć w odpowiedniej kolejnośći. Czy jest na to jakiś pattern z mądrych ksiązek - szukałem a nie znalazłem. wiem, że istnieje przeciwieństwo - competitive receivers, ale to bym nazwał competitive producers - tylko, ze nie ma czegos takiego.

1

(pytanie)

a gdyby dodać 2 timestampy - jeden to moment wysłania (czas od klienta który powinien zapewnić że kliknięty pierwszy miał w sobie wcześniejszy czas niż kliknięty drugi request (chociaż przy zmianie czasu? ;))) oraz drugi tak just in case, jakby ktoś hakował - timestamp zapisu po naszej stronie

3

Jedną z opcji jest wrzucenie eventu znowu na kolejkę.

Jeżeli przyszło OrderCancelled, a nie ma OrderCreated to wrzucasz OrderCancelled na kolejkę z nowym timestampem i z podbitym retry'em. Po kilku takich retry'ach po prostu odrzucasz event, żeby nie rolował się w nieskończoność.

2
1a2b3c4d5e napisał(a):

(pytanie)

a gdyby dodać 2 timestampy - jeden to moment wysłania (czas od klienta który powinien zapewnić że kliknięty pierwszy miał w sobie wcześniejszy czas niż kliknięty drugi request (chociaż przy zmianie czasu? ;))) oraz drugi tak just in case, jakby ktoś hakował - timestamp zapisu po naszej stronie

Co wtedy kiedy jest problem z synchronizacją zegarów, np. masz dwie instancje A i B i na A zegar systemowy się śpieszy o kilka minut?

Ktos wysle te 2 komunikaty praktycznie naraz, jeżeli OrderCancelled dojdzie pierwsze to pojdzie na straty, my nie chcemy stracić tego eventu a je ułożyć w odpowiedniej kolejnośći

Dla mnie to nie jest jakiś ciężki przypadek - jeżeli wiemy że najpierw było canelled a później przyszło create to można to opędzlować - skoro dotyczy tego samego.
Poza tym w takiej Kafce masz teoretycznie zachowaną kolejność jako że to jest dystrybuowany log.

1
1a2b3c4d5e napisał(a):

(pytanie)

a gdyby dodać 2 timestampy - jeden to moment wysłania (czas od klienta który powinien zapewnić że kliknięty pierwszy miał w sobie wcześniejszy czas niż kliknięty drugi request (chociaż przy zmianie czasu? ;))) oraz drugi tak just in case, jakby ktoś hakował - timestamp zapisu po naszej stronie

W monolicie jeszcze jako tako, ale w srodowisku rozproszonym timestamp nie daje ci gwarancji kolejności biznesowej, załóżmy, ze orderCreated bedzie długo coś przetwarzał, albo latency bedzie duże do orderCreated i zanim odbierze to juz inny serwis z cancelled sobie 2 razy wysle.

Tez takiej inicjalizacji musialbys dokonowywać na wstepie serwisu i wszedzie ten timestamp ciagnac. Taki strukturalny coupling eventu poprzez namaszczenie go inicjalnym timestampem, nie czuje tego, ale dzieki za komenatrz.

twoj_stary_pijany napisał(a):

Jedną z opcji jest wrzucenie eventu znowu na kolejkę.

Jeżeli przyszło OrderCancelled, a nie ma OrderCreated to wrzucasz OrderCancelled na kolejkę z nowym timestampem i z podbitym retry'em. Po kilku takich retry'ach po prostu odrzucasz event, żeby nie rolował się w nieskończoność.

Ja myślałem, że jak już to do bazy zapakować i sobie odtwarzać, ale na kolejke tez sie da, Wiesz moze czy moj lub twoj pattern ma swoja nazwe, bo cos czuje, ze nie pierwszy sie spotykam z tym problemem.

0

@scibi_92:

Co wtedy kiedy jest problem z synchronizacją zegarów, np. masz dwie instancje A i B i na A zegar systemowy się śpieszy o kilka minut?

Masz jeszcze wtedy timestampy od usera

@DKN:

Tez takiej inicjalizacji musialbys dokonowywać na wstepie serwisu

o tym myślałem, aby go przypiąć na samym początku i ciągać dalej

widziałem coś takiego chyba z guidem do trackingu requestów pomiędzy mikroserwisami na jakiejś prezentacji, ale to było w celu debugowania iirc.

2

@1a2b3c4d5e:

  1. Chcesz userowi pozwalać na decydowaniu o takiej mutacji danych? Backdoor taki ze hej.
  2. Mowisz pewnie o latency trackingu, spring Sleuthu, ramkach b3, w3. Zipkine. To coś innego. Tym mierzymy czas polaczeń. Staramy sie odpowiedzieć na pytanie, gdzie znajduje się wąskie gardło..
0

@DKN:

Backdoor taki ze hej.

czemu? wydaje mi się że zależy jak wokół tego zagrasz, np. aby używać tych danych do próby naprawienia stanu systemu

1

Chodzi Ci o to by zapisywac na bazie a pozniej interwalo sprawdzac potencjalne eventy ktore przyszly wczesniej?

Tak

Co to oznacza, ze na kafce masz zachowana kolejnosc? Kafka uklada sobie te rzeczy czasowo, ale nie biznesowo. Moze do kafki przyjsc najpierw cancelled

Chodzi mi o to

1

@1a2b3c4d5e:
tzn. to bedzie moglo spelniac mala funkcje, ale jest dziurową trytytką.
Jezeli 2 userow pracuje na 1 koncie i maja inna strefe czasowa. ?
Czesto sie zdarza, ze w ramach jednego konta grupowego uzyszkodnicy dokonuja zmian.

2

Już ci to napisali, ale spróbuję:
Wpada ci event CancelOrder na nieznane zamówienie
Nie możesz go obsłużyć, czyli nie dajesz ack na kolejce, czy tam zwracasz 400-ileś zależy z czego korzystasz
Po jakimś czasie, najczęściej w zależności od ustawień kolejki dostajesz tę samą wiadomość ponownie, albo jesteś w stanie ją przetworzyć, albo nie i w zależności od tego albo ack, albo znowu nic
Po iluś tam próbach wiadomość ląduje w deadletter skąd możesz ją albo wywalić, albo diagnozować co się stało.

Trochę to zależy od użytej kolejki, ale ogólnie funkcje takie jak PeekLock i Acknowledge są dostępne wszędzie, podobnie ja ustawianie czasu blokowania wiadomości i liczby prób dostarczenia.

0

https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/

Zapisujesz w bazie i stamtąd wrzucasz na Kafkę zachowując kolejność.

2

Są na to różne sposoby.

Jeden to np. Saga która w swoim stanie przechowuje eventy które jeszcze nie powinny zostać przetworzone, i przetwarza je dopiero kiedy Saga wejdzie w odpowiedni stan. To oczywiście wymaga użycia odpowiedniego podejścia i albo zaimplementowanie tego samemu, albo znalezienie gotowego rozwiązania.

Innym jest oddelegowanie tego do brokera, i użycie np. sesji (nazwa różni się zależnie od użytego brokera). Wtedy mamy zapewnione że konkretna subskrypcja dla correlation ID będzie otrzymywać eventy w kolejności, ale możliwym kosztem skalowalność (chociaż czy to problem zależy od skali systemu).

Jeszcze innym to obsługiwanie eventów z nastawieniem na to że coś takiego może się wydarzyć. Przyszedł event OrderCancelled ale zamówienie z takim ID nie istnieje? To je utworzę i odpowiednio oflaguje jako anulowane. W handlerze OrderCreated natomiast będę robił upsert i ustawiał tylko te właściwości zamówienia które są ważne dla tego eventu, tak aby nie zmieniać statusu zamówienia jeśli zostało już anulowane.

1 użytkowników online, w tym zalogowanych: 0, gości: 1