serwer WWW a serwer backendowy

0

Hej, realizuje jeden z projektów na studia, gdzie jednymi z wymagań sa:

- System sklada sie z dwoch procesow: serwera WWW i serwera backendowego, przetwarzajacego zlecenia. W ten sposob system powinien izolowac serwer www od przetwarzania bazodanowego za pomoca kolejek.
- Generalnie mozna wyroznic 2 rodzaje komunikacji zlecenia (komendy itd), wymagajace zmiany stanu bazy i zapytania(selecty), tj. np. selecty na potrzeby np. autoryzacji, wyswietlenia stanu inicjalnego.
- Zlecenia powinny oczekiwac w kolejce na przetworzenie, a wynik powinien byc zwracany przez kolejki do serwera WWW. Po wyslaniu zlecenia serwer sterowanie wraca do aplikacji WWW, a ta np. przy pomocy WebSocket aktualizuje swoj stan po przyjsciu odpowiedzi

Czy moglby mi ktos wytlumaczyc co powieniem rozumiec jako serwer www? chodzi o to, ze serwer www to backend A, do ktorego bedzie sie komunikowal frontend, a ten backend A bedzie korzystał z backendu B(nazwanego serwerem backendowym) gdzie bedzie odbywac sie cala "logika"?

1

Dla autora serwer WWW to "frontend" który komunikuje sie z backendem asynchronicznie przez kolejki. W sensie masz normalną aplikacje webową, która komunikuje się pod spodem z jakimś innym serwisem, który tutaj nazywa się serwerem backendowym.

0

hmm, ok ale chyba nie rozumiem ogolnego koncpetu. Zalozmy, ze wołam endpoint A, który wrzuca działanie X do kolejki(zalozmy, ze jest to rabbitMQ ale to chyba nie powinno miec znaczenia) i jak zwracamy wynik tego działania do osoby, która wołała? Jesli dzialanie bedzie w kolejce to nie wiemy kiedy sie wykona dlatego nie czekamy na wynik wiec inna opcja to uzycie webhooków zeby poinformowac o wyniku ale webhooki uzywamy na backendzie a nie na frontendzie wiec nie wiem.

0

bylbym wdzieczny za tytul jakiejs ksiazki/bloga gdzie moge znalezc informacje jak budowac systemy w oparciu o CQRS i kolejki bo chyba popelniam jakies bledne zalozenia w moim rozumowaniu

1

Masz napisane że są tam websockety :) Nie czekasz aktywnie na wynik na froncie tylko masz websocket na który przyjdize odpowiedź.

0

Ale gapa ze mnie :D dzieki!
w przypadku CQRS i kolejk to ma wygladac tak, ze kazda komenda(cqrs) trafia do kolejki i pozniej na wynik trzeba czekac w przypadku frontendu na websokecie? W przypadku zapytan(cqrs) nie wrzucamy tego do kolejki tylko synchronicznie zwracamy zasób?

tldr; czy to oznacza, ze kazdy event musi trafic do kolejki i wtedy ewentualny wynik dostaniemy przez websocket a w przypadku quries mozemy dostac wynik synchronicznie?

2

Musisz jeszcze jakoś zagwarantować, że widok zbudowany na froncie z danych przesłanych przez WS jest spójny z wynikiem synchronicznego zapytania, kiedy np. odświeżysz stronę. Możesz to zrobić stosując coś a la event sourcing, czyli query zwraca sekwencje zdarzeń od samego początku - wtedy na frontendzie masz jeden kod składający te eventy, nieważne czy pochodzą z WS czy z query. Możesz tez zrobić odwrotnie - po przetworzeniu komendy aktualizujesz model danych, a przez WS pchasz cały agregat zamiast zdarzeń/delt i frontend w ogóle nie zajmuje się składaniem eventów - tak bym chyba nawet proponował.

0

Nie jestem pewien czy dobrze zrozumialem pierwszy komentarz - mam po stronie frontu wrzucac bezposrednio do kolejki commandy/queries? Nie powinno byc tak, ze najpierw robie request na backend i to backend wrzuca command/query do kolejki?

2

Wysyłanie żądania z przeglądarki bezpośrednio do kolejki jest złym pomysłem. Powinieneś mieć wystawione API w formacie wygodnym dla klienta, czyli pewnie jakiś REST. Ten sam komponent może wystawiać inne API dla klienta, np. w celu pozyskiwania danych do wyświetlenia. W przeciwieństwie do @Charles_Ray nie uważam, żeby przesyłanie wszystkich rekordów do klienta i przerzucenie na niego odpowiedzialności ustalenia stanu wynikowego. CQRS zakłada, że masz od tego osobny serwis (część Q). Pchanie przez internet do przeglądarki całej historii np. konta klienta, tylko po to, żeby określić aktualne saldo zdecydowanie mi nie pasuje, chociażby ze względu na ilość danych przesyłanych przy każdym żądaniu.

0

Dzieki! :)

Mam jeszcze bardziej ogolne pytanie - czy jest sens stosowania DDD lub nawet CQRS w projektach, które nie są wielkimi kobyłami tylko prostymi projektami skladajacymi sie z prostych CRUDów?

2

Nie ma. Nawet w aplikacjach które nie są tylko CRUDami ale logika biznesowa jest w nich prosta. Chociaż akurat "logiczne" CQRS w takim przypadku warto stosować, w sensie stosowny podział na klasy przetwarzajace polecenia i zapytania. Nie oznacza to natomiast ze pewnych elementów DDD nie warto stosować w takim przypadku. Takie "lekkie" DDD jak najbardziej może mieć sens. Ale wiadomo- to zależy.

0

@Aventus czyli uważasz, że "zabawa" w eventy itp. nie ma wiekszego zazwyczaj sensu (tj. nie ma korzysci z poswieconego dodatkowego czasu na pogodzenie wszystkiego z zasadami DDD)?

2

W celu nauki raczej warto :P

1

Tak jak pisze WeiXiao jeśli to w celu nauki to czemu by nie? W przeciwnym razie nie za bardzo.

Przy użyciu lekkiego DDD możesz pominąć eventy, ale np. nadal rozbić aplikacje na konteksty. Jeśli to monolit to komunikacja między kontekstami może się odbywać za pomocą wysyłania poleceń i oczekiwania na wynik.

0

Zgadzam sie i postaram sie do tego przylozyc, zeby projekt jak najwiecej mial wspolnego z CQRS i DDD.

PS: Mam pewien dylemat z zamodelowaniem encji do mojego problemu. Zalozmy, ze chce zrobic np. system do rezerwacji cos typu booking.com czyli, ze mam encje Pokoj i mam encje Rezerwacja.

Moglbym zrobic takie cos: encja Rezerwacja posiada atrybuty takie jak ID, odKiedy, doKiedy, referencje do pokoju (czyli many-to-one) a encja Pokoj posiada ID (dla uproszczenia zalozmy, ze tylko ID).

Czy bedzie dobrym posunięciem dodanie kolejnego atrybutu STATUS (zajety/wolny) do encji Rezerwacja? Wtedy w bazie zawsze bylby np. rezerwacje z okresem na 200 dni do przodu (1 rezerwacja per 1 dzien per 1 pokoj) i jesli nie byloby rezerwacji do danego pokoju to bylby Status.Wolny, a w przeciwnym wypadku Status.Zajety.

Powodem ku zrobieniu czegos takie jest problem z ewentualnym query gdzie chce pobrac wolne pokoje w okresie 20.09.2019-24.09.2019 - bez atrybutu Status musialbym pobierac wszystkie rezerwacje i wyliczac, w ktorych dniach pokoj jest wolny na podstawie tego, ze nie bedzie w bazie rekordu rezerwacji w danym terminie bo w bazie zapisujemy tylko faktyczne rezerwacje, ktore zajmują dany pokoj w danym terminie.

Oba rozwiazania wydaja mi sie jednak slabe i brzydkie. Co o tym sadzicie?

1

Widzisz, i tutaj pojawia się kwestia właśnie używania DDD bo siłą rzeczy trzeba trochę "skomplikować" w takiej sytuacji. Jeśli podzielisz aplikację na konteksty (bounded contexts) to każdy kontekst powinien mieć swoje dane i encje. Możesz np. mieć kontekst Rooms zajmujący się zarządzaniem pokojami, i w nim coś w stylu ReservedRoom który będzie posiadał Id do Room żeby oczywiście wiadomo było o jaki pokój chodzi jak i szczegóły rezerwacji- data od, do. Być może również numer/id rezerwacji.

1

Myślę, że problem okazałby się dużo prostszy, gdybyś nie zakładał z góry, że ORM'y załatwią całą sprawę, bo pozwalając sobie na nieco bezpośredniej interakcji z bazą danych problem staje się dość banalny, ale niestety zależny dość mocno od RDBMS, który będzie w użyciu. Trzymałbym jedynie istniejące rezerwacje zawierające interwał od-do, po stronie bazy danych użył odpowiedniego typu, np. https://www.postgresql.org/docs/9.3/rangetypes.html w celu szybkiego działania całości dorzucił do tego indeks r-tree. Wyciągnięcie wolnych pokoi w jakimś tam zakresie dat jest w tym układzie kwestią jednego, poprawnie napisanego zapytania SQL.

1

Jeszcze małe pytanko. Piszac testy integracyjny wpadlem na pewien problem bo chce przetestować w kontrolerze przypadek, ze ktos chce zarezerwowac zarezerwowany pokoj. Robi POSTem rezerwacje czyli mam w tym przypadku Command. Problemem jest to, ze komendy wrzucam do kolejki więc tak na prawde nawet jak ktoś bedzie chcial zarezerwowac pokoj zarezerwowany to bede musial zwrocic 200 jesli nie chce wymuszac oczekiwania na wynik z kolejki. Czy to jest w porządku w przypadku CQRS? Czy moze moge sobie pozwolic na taką "głębszą" walidację sprawdzającą czy komenda ma szanse na powodzenie?

Albo co zrobic, jak zwroce uzytkownikowi 200 bo walidacja przeszla ale w command handlerze poleci jakis exception, ktorego nie mozna bylo wczesniej przewidziec?

1

CQRS moim zdaniem niejako wymusza przejście od strong consistency do eventual consistency. Czyli wiele klientów może w zbliżonym momencie wygenerować intencje i wrzucić je do kolejki. Serwis, który przetwarza intencje dokonuje odpowiedniego wpisu w bazie danych dla pierwszej intencji i ignoruje pozostałe. Dokonanie, bądź brak możliwości dokonania rezerwacji są przekazywane klientom asynchronicznie przez Web Socket. Bardziej prawidłowym statusem będzie HTTP202 - zaakceptowane do przetwarzania, ale to oczywiście jedynie drobny szczegół dla poprawienia czytelności API.

4

@piotrpo: jak wiele osób mieszasz trochę czym jest CQRS. Zwróć uwagę że wspomniałeś o nim i z góry założyłeś obecność kolejkowania. Nic bardziej mylnego. CQRS to fundamentalnie niebywale prosta koncepcja- podział na klasy przetwarzające polecenia (modyfikujące stan aplikacji) oraz zapytania (sam odczyt). To o czym Ty piszesz to CQRS podniesiony do poziomu infrastruktury. Ale w żaden sposób nie przeczy to temu że CQRS może, i jest znacznie prostsze.

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