Szukam jak najlepszego rozwiązania do radzenia sobie z równoległymi operacjami na tej samej encji biznesowej w przypadku gdy mam do czynienia z możliwością równoległego przetwarzania wiadomości zmieniających stan danej encji biznesowej.
Powiedzmy, że mamy system A, oparty na kolejce (jako warstwa transportu Apache kafka). Do integracji z frontem używany jest REST API
działającej na zasadzie:
- przyjmij zadanie
- zakolejkuj
- zwróć 202.
Ponadto aplikacja integruje się z innymi mikrousługami w podobny sposób.
Przybliżony problem
- Użytkownik inicjalizuje process w systemie A (tworzymy encje biznesowo)
- Podczas inicjalizacji procesu, zakładamy asynchroniczne zadania w innych systemach (powiedzmy w systemach B i C)
3a) Użytkownikowi pozwalamy działać dalej i może uzupełniać dalsze dane (modyfikuje encję biznesowo)
3b) system A może zacząc przetwarzać wynik zadania z systemu B i C (pobranie z kolejki) i dorzucić te dane do encji biznesowej. - Użytkownik po kroku 3a w systemie A wykonuje akcję, która w zależności od tego czy dane z kroku 3b dojdą czy nie wykona się inaczej (Przy czym dane z systemów B i C i tak finalnie muszą zostać dociągnięte, gdyż będzie miało to finalnie wpływ na dalsze kroki)
Na tym etapie, może się zdarzyć, że operacje 3a z (3b lub 4) nastąpią w tym samym czasie i może dojść do konfliktu.
Większość porad ogranicza się do stosowania albo Optimistic Concurrency albo pessimistic concurrency.
przy czym w wersji:
- Optimistic Concurrency - w przypadku wykrycia konfliktu musiałbym zapewnić jakoś, żeby wiadomość jednak została potem jeszcze raz przetworzona po jakimś czasie np. poprzez opublikowanie jeszcze raz wiadomości co trochę przeczy idei tego podejścia, której celem miało być, że w przypadku dwóch zadań, tylko jeden się wykona.
- Pessimistic concurrency. - poległo by na zakładaniu rozproszonej blokady (np. przy pomocy redlocka redisa, lub bazy danych) na handlerze wiadomości po wspólnej korelacji dla procesu. Tutaj problem pojawia się taki, że takie podejście raczej będzie miało negatywny wpływ wydajnościowy + powinno się założyć jakiś rozsądny maksymalny czas życia blokady, więc i tak mogłyby nastąpić przypadki, że jedno zadanie po jakimś czasie może niepożądane zacząć się procesować. Plus dochodzi kwestia, że powinno w jakimś ograniczonym czasie albo zatwierdzić albo nie zczytanie wiadomości w kafce inaczej inna instancja aplikacji zacznie czytać wiadomość z danego topica.
- Zapewnienie już na kolejce, że wszystkie wiadomości dla jakiejś korelacji by były przetwarzane sekwencyjnie lecz szukając w internecie nic takiego na ten moment nie znalazłem w przypadku kafki.
- Może ogólnie nie należy bawić się w blokady a dociągane w tle dane odkładać jakoś na boku a dopiero na jakimś etapie procesu gdzie np. nie będzie możliwości wykonania akcji przez użytkownika wykonać uzupełnienie encji biznesowej, żeby wpadła w ostatecznie spójny stan.
Co o tym myślicie, może znacie lepsze podejście dla takich przypadków?