Mikroserwisy - validacja danych pomiędzy serwisami

0

Witam.
Zacznę od tego, że dopiero uczę się tej architektury ;)
Piszę prosty sklep (mamy produkty i zamówienia).
Przy składaniu zamówienia mamy listę produktów jak i cenę zamówienia.
I tu mam właśnie problem jak to rozwiązać poprawnie, bo wiadomo bezpośrednio nie mogę się do innego serwisu odwołać a chcę sprawdzić przede wszystkim : czy produkt nadal istnieje i mieć jego cenę (do sumy łącznej zamówienia).
Mam pytanie odnośnie tego właśnie.
Czy jest jakiś sposób by z Seriwsu A wysłać wiadomość do serwisu B (np. o ten mój produkt do zamówienia) i jakoś dostać zwrotną? Inaczej niż sub do eventu i czekać aż pojawi się event z id mojego produktu?

3

Czy jest jakiś sposób by z Seriwsu A wysłać wiadomość do serwisu B (np. o ten mój produkt do zamówienia) i jakoś dostać zwrotną?

Wyślij zwyczajne żądanie HTTP z jednego serwisu do drugiego - nie wszystko musi iść przez setki kolejek, piętnaście baz danych, event sourcing i sagę.

2

Ogólnie w ogóle nie możesz w jednym mikroserwisie czekać na odpowiedź drugiego serwisu, ponieważ gdy ten drugi serwis zawiedzie, pierwszy też nie będzie w stanie dać klientowi odpowiedzi. Zazwyczaj rozwiązuje się to przez pewną redundancje danych. Czyli obydwa serwisy powinny zawierać część tej samej informacji. W Twoim przypadku możesz mieć w serwisie A pełne informacje o produktach (cena, stan, opis, itd.) a w serwisie B tylko cenę i czy jest dostępny. Takie cachowanie danych odbywa się z pomocą eventów integracyjnych.
Masz też opcję numer dwa - pobrać odpowiednie dane z serwisu A na poziomie Gateway API, a następnie wysłać je do serwisu B.

0

Już wiem, po prostu miałem taki błędny ciąg myślowy z którego nie potrafiłem wyjść. Sądziłem, że to co napisałeś również nie rozwiąże sprawy, ale jeżeli Serwis Catalog będzie słał do Message Bus informację, że dany produkt został zaktualizowany to Serwis Order to odbierze i zaktualizuje po swojej stronie i to mi rozwiąże problem z walidacją ;)
Dziękuję ;)

1

Pozwolę sobie dodać dwa grosze ponieważ odpowiedź @LagMan jest poprawna, a jednocześnie błędna ;) Zależy od kontekstu. W Twoim konkretnym przypadku to się sprawdzi, ale załóżmy czysto hipotetycznie że sklep o który mowa handluje unikalnymi i drogimi produktami których jest mało na stanie i nie można ich doprodukować. W związku z tym jednym z wymogów biznesowych jest to aby zamówienie złożone na już wyprzedany produkt zostało natychmiast odurzone. Dla przykładu przyjmijmy że mamy dodatkowy serwis Warehouse, który odpowiada za pilnowanie aby poinformować o braku dostępności danego produktu. Samo komunikowanie eventów o zmianie stanu nie wystarczy ponieważ nie możemy na tym w pełni polegać- serwis Ordering może posiadać błędną ilość danego produktu.Przypominam że w tym fikcyjnym scenariuszu jednym z wymogów jest natychmiastowe odrzucenie zamówienia. W wielu rzeczywistych przypadkach wystarczyłby mail z przeprosinami i zwrot pieniędzy.

Jak więc sobie poradzić z rozproszonymi serwisami komunikującymi się asynchronicznie? Można wykorzystać Process Manager dla każdego procesu biznesowego angażującego więcej niż jeden serwis, np. składanie zamówienia. Wtedy taki manager koordynuje komunikację między serwisami- odbiera eventy i wysyła polecenia (commands). Pierwszy request wysyłany od klienta do serwisu rozpoczyna proces. Odpowiedź serwisu- np. 200 OK- w tym przypadku nie oznacza powodzenia całego procesu a jedynie przyjęcie polecenia. Klient zostaje poinformowany o sukcesie lub porażce procesu za pomocą dwustronnej komunikacji klient-serwer, np. przy użyciu SignalR. Aby to zobrazować, taka komunikacja mogła by wyglądać następująco:

  1. Klient wysyła zamówienie za pomocą HTTP
  2. Serwis Ordering rozpoczyna proces emitując event OrderPlaced
  3. OrderProcessManager odbiera OrderPlaced i emituje polecenie ReserveItem
  4. Serwis Warehouse odbierage ReserveItem:
    Jeśli przedmiot jest na stanie to serwis emituje ItemReserved, w przeciwnym razie zostaje wysłany event ItemReservationFailed
  5. OrderProcessManager odbiera jeden z eventów z serwisu Warehouse
    Zależnie od odebranego eventu, OrderProcessManager zakańcza z powodzeniem proces lub tworzy błąd- jest to wysłane do klienta za pomocą SignalR
  6. Klient- który właśnie wyświetla np. spinnera informującego użytkownika o trwającym składaniu zamówienia- odbiera wiadomość poprzez SignalR i na jej podstawie podejmuje dalsze działanie: przekierowuje użytkownika do strony płatności lub wyświetla błąd zamówienia.

W powyższym przykładzie po stronie klienta nadal można użyć timeout (wymieniony w komentarzach wyżej), ale jest on jedynie ostateczną linią obrony kiedy zawiedzie strona techniczna- proces nie zakończy się z powodu niedocierających eventów lub zawiedzie komunikacja poprzez SignalR.

0

Zgodnie z https://en.wikipedia.org/wiki/CAP_theorem w przypadku niemożliwości połączenia się między serwisami (w szczególności: gdy jeden serwis po prostu nie działa - tak mi się wydaje) trzeba wybrać między dostępnością, a spójnością. W zależności od tego co wybierzesz do wyboru będą inne rozwiązania.

0

. Zastanawiam się po prostu czy po stronie serwisu - order, muszę obsługiwać jakiś event typu ProductPrice, któy jest odpowiedzią na command GetProductPrice, jednak to jest kruche rozwiązanie, bo mogę odebrać nie ten event (nie od tego zamówienia)

@kenik: z czego korzystasz do komunikacji? RabbitMQ umożliwia oczekiwanie na odpowiedź dla konkretnej komendy - https://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html

0

Tak, używam RabbitMq i MediatR.
W moim przypadku wydaję mi się, że to wystarczy, że będę miał Produkt z jego ceną i odpowiednie eventy wysyłane do Busa jak np. utworzony produkt/edytowana cena czy usunięty produkt.

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