Wiele instancji, jedna baza, eventy i odpowiedzialność za utrwalanie danych

Wiele instancji, jedna baza, eventy i odpowiedzialność za utrwalanie danych
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0
  • Załóżmy że mamy sobie jakiś serwis X, który ciągnie sobie dane z jakiejś SQLowej bazy danych i tam też chciałby utrwalać zmiany.
  • Załóżmy że możemy mieć N instancji tego serwisu.
  • Załóżmy że chcemy tam użyć subscription z GraphQL, więc chcemy informować frontend o zachodzących zmianach (czyli frontend nie robi nowego requestu po dane, tylko dostaje od nas websocketem delty)
  • Załóżmy, że chcemy trzymać stan aplikacji w pamięci i nie ładować przy każdym requeście rzeczy od zera z bazy (to tylko dla ustalenia uwagi, bo niczego to specjalnie nie zmienia tutaj)

Problem: przychodzi jakiś POST z frontendu (czy tam mutacja z GraphQLa) i teraz potrzebujemy:

  • Przepuścić to przez logikę domenową, żeby sprawdzić czy ta operacja w ogóle ma sens
  • Jeśli tak, to potrzebujemy poinformować frontend o zmianie + potrzebujemy zmianę utrwalić w bazie
  • Jak nie trudno zauważyć, potrzebujemy też jakoś poinformować inne instancje o tym że zaszły zmiany, żeby mogły odpowiednio updatować swój stan oraz poinformować klientów frontendu którzy są do nich wpięci

Najbardziej oczywiste rozwiązanie byłoby takie:

  • Instancja która odebrała request przepycha to przez logikę domenową i jeśli request ma sens, to utrwala zmiany w bazie, emituje event dla innych instancji i informuje swoich klientów o zmianach
  • Pozostałe instancje odbierają event, przepychają go przez logikę domenową i informują swoich klientów o zmianach

Nie podoba mi sie tutaj trochę to, że w sumie mamy tu 2 flowy. Można by to mocno uprościć, gdyby instancja która odebrała request po prostu emitowała automatyczne event, a potem wrzucenie tego w logikę domenową plus informowanie klientów odbywało się z event handlera. Tylko że pojawia się tutaj problem persystencji, bo ktoś to finalnie musi zapisać do bazy a w takim modelu nie bardzo wiadomo kto powinien być za to odpowiedzialny.

Oczywiście można by dołożyć jeszcze drugi serwis, który łykałby event i zajmował się tylko zapisywaniem zmian w bazie, czyli takie trochę CQRS, bo wtedy serwis X byłby tylko od czytania a ten nowy serwis zajmowałby się pisaniem, ale mam wątpliwości czy uda mi się przepchnąć taki design...

Da się to jakoś sprytniej zrobić? Nitka idź!


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
WeiXiao
@Aventus: chyba twoja ulubiona działka ;)
Shalom
Tylko proszę tutaj bez jakichś ewangelizacji DDD :D
PI
Nie wierzę, Shalom dodał post pytając o coś!!!
Shalom
@Pinek: przecież to nie pierwszy raz :P to jest tzw #gruparatowaniapoziomu
katakrowa
  • Rejestracja:około 10 lat
  • Ostatnio:około 2 lata
  • Lokalizacja:Chorzów
  • Postów:1670
1

Te N instancji rzeczywiście daje do myślenia jednak mimo, że godzina robi się już późna to obstaję, że Najbardziej oczywiste rozwiązanie byłoby całkowicie OK.
Jakie korzyści da Ci ten drugi serwis?
Czy już masz wiedzę o tym, że będą kłopoty z wydajnością (to by uzasadniało)?
Czy jest jakaś inna przyczyna żeby to rozdzielać?

I skoro gdyby instancja która odebrała request po prostu emitowała automatyczne event to mam naiwne pytanie:

  1. Czy do wszystkich frontendów czy do aplikacji (kto jest odbiorcą tego zdarzenia)?
  2. Jeśli do front-endów to czy one na 100% nie dostaną go zanim zmiany zapiszą się w bazie?

No i w sumie czy te poszczególne instancje o sobie wiedzą? Czy to w nich jest zaszyta logika biznesowa a część wspólna to jedynie baza? Jeśli się nie "widzą" to zakładając, że ilość zapisów jest znacząco mniejsza i mniej obciążająca niż odczyty to może ten nowy "serwis" zapisujący wepchnąć właśnie między instancje a bazę. Wówczas on będzie emitował komunikat po zmianie danych.


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.
edytowany 3x, ostatnio: katakrowa
WeiXiao
  • Rejestracja:około 9 lat
  • Ostatnio:około 3 godziny
  • Postów:5105
0

Załóżmy że możemy mieć N instancji tego serwisu.

mieć możemy, a chcemy?

Zobacz pozostały 1 komentarz
WeiXiao
zerowym downtime rozważałeś może mainframe + z/OS? dobra, sam wyjdę :D
Shalom
Myślałem że to raczej normalna praktyka, że wypina sie instancje z load balancera, updatuje wersje, restartuje i wpina ponownie i tak dla każdej instancji ;) Na mainframe sie nie znam.
AF
W mainframe jest troszkę prościej, bo wypina się go z firmy, wyłącza i nigdy nie wpina ponownie.
WeiXiao
@Afish oj tam, ciekawa technologia.
AF
Wiem, sam z nią pracowałem.
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Czy do wszystkich frontendów czy do aplikacji - kto jest odbiorcą tego zdarzenia?

Nie no jak do frontendów niby? Wiesz ty jak działają websockety? :D Mówie o emitowaniu eventów do innych instancji serwisu, bo tylko one mają websocketowe połączenia z klientami.
Problem z tym oczywistym rozwiązaniem jest taki, ze masz w aplikacji bardzo podobną logikę w dwóch miejscach (w obsłudze requestu i w obsłudze eventu) i to mi się nie podoba. Korzyść z drugiego serwisu jest właśnie taka, że ta druga logika wylatuje w inne miejsce i ten dualizm znika. Nie ma to nic wspólnego z kwestią wydajności akurat, bo przecież bottleneck to i tak będzie baza.

Jeśli do front-endów to czy one na 100% nie dostaną go zanim zmiany zapiszą się w bazie ?

Jakie to w ogóle ma znaczenie? Przecież frontend nie czyta nic z bazy o_O Niemniej event leci do backendowego serwisu, więc jak frontend dostanie informacje o zmianach to dana instancja już będzie miała te zmiany "zaaplikowane" tak czy siak. Zresztą te websocketowe informacje do frontu są jakoś magicznie używane przez graphql, tak ze on nie robi dodatkowego requestu do backendu, tylko modyfikuje sobie stan klienta na ich podstawie :)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 2x, ostatnio: Shalom
katakrowa
niestety nie wiem co dokładnie robi graphql stąd moje być może naiwne pytania bo podchodzę do niego jedyni jako do "protokołu" komunikacji.
katakrowa
  • Rejestracja:około 10 lat
  • Ostatnio:około 2 lata
  • Lokalizacja:Chorzów
  • Postów:1670
0
Shalom napisał(a):

Nie no jak do frontendów niby? Wiesz ty jak działają websockety?
Jakie to w ogóle ma znaczenie? Przecież frontend nie czyta nic z bazy o_O

Wiem jak działają .. zapędziłem się.

Nie wiem natomiast jaka jest komunikacja pomiędzy aplikacją=instancją a podłączonym do niej klientem=front-endem. Czy aplikacja zna "stan" front-endu? Czyli wie jaka "encja/opcja" jest w danym momencie otwarta i jakie rodzaje komunikatów jest sens wysyłać? Z opisu zrozumiałem, że aplikacja śle do forntu każdą zmianę z danymi (deltą)? Co jednak w przypadku kiedy front-end tej zmiany w danym momencie nie potrzebuje - czy wtedy te komunikaty latają na darmo?


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.
edytowany 1x, ostatnio: Shalom
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

@katakrowa to jest trochę obok tematu, bo nawet gdyby tych notyfikacji do frontu nie było, to nadal nie zmienia wyjściowego problemu ;) Z tym graphqlem to takie trochę testy robimy, możliwe że w ogóle ten pomysł wyleci, ale póki co frontedowiec chciał spróbować z tego korzystać. Niemniej: https://www.apollographql.com/docs/react/data/subscriptions/ więc klient decyduje o tym co go interesuje generalnie.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
katakrowa
Generalnie ciekawe i zawsze interesują mnie takie tematy jednak w tym przypadku chyba potraktowałem temat zbyt ogólnikowo a brakuje mi jakiegoś środowiskowego (Javowego?) obycia żeby dokładnie zrozumieć koncepcję co dokładnie "lata" w tych komunikatach, które rzeczy dzieją się automatycznie itp ... Także raczej zrezygnuję z dalszego nietrafionego doradzania :-) Życzę jednak by jakiś pomysł się znalazł.
UglyMan
  • Rejestracja:około 6 lat
  • Ostatnio:około 3 lata
  • Postów:2206
1

Czyli jak dobrze rozumiem (ja to bym chyba potrzebował jakiś rysunek, żeby to zrozumieć). Przychodzą dane wpadają na jedną z instancji i zostają przetworzone. Jak jest ok to idą do zapisu na bazie i pozostałe instancje są informowane o tym, że muszą podesłać przez websoceta dane gdzieś w świat. Czy instancje powinny zaczekać na zapis danych i dopiero je odesłać?
Nie rozumiem, po co te same dane pchać przez logikę domenową "odczytujące" i wysyłając przez websoceta - jak jedna instalacja przejedzie je logiką to potem można jest wysłać w świat (nie znam GraphQLa i to może tu się tak nie da)? Tak na mój prosty rozum to by się przydała jakaś kolejka - jedna instancja przerabia dane pakuje w kolejkę a reszta odczytuje. Do tego DB zapisywacz - który tez jest zapięty na kolejkę.

katakrowa
Rysunek mocno wskazany. W swoim chyba nie do końca zrozumieniu problemu to samo zaproponowałem ale ponoć nie o to chodzi. Proponowałem ten nowy "serwis" zapisujący wepchnąć właśnie między instancje a bazę o on byłby wówczas źródłem komunikatu. Niejasne dla mnie też pozostaje co znaczy aplikacja "trzyma stan". Stan czego. Swój stan, stan każdego front endu i co dokładnie lata między frontem a instancją.
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Czy instancje powinny zaczekać na zapis danych i dopiero je odesłać?

To raczej bez znaczenia dla nich, jeśli w evencie dostaną informacje o tym co się zmieniło. Jak event zawiera informacje user zmienił maila na a@b.cd to możemy sobie tą zmianę "wprowadzić" gdzieś do obiektów domenowych w pamięci niezaleznie od tego czy zmiana już jest w bazie czy jej tam nie ma.

Nie rozumiem, po co te same dane pchać przez logikę domenową "odczytujące"

Ja tu nie mówie o walidacji, albo nie tylko o walidacji, ale po prostu o "wykonaniu akcji". Tzn. user zmienia jakiśtam tryb działania aplikacji, więc chce sobie znaleźć tego usera, jeśli mam go załadowanego w pamięci, i zmienić mu ten tryb, plus wykonać wszystkie operacje które to za sobą pociąga. Tak żeby kolejny request do tej instancji zwracał poprawne wyniki. Pisałem gdzieś wyżej, że chce uniknąć "ładowania od zera" przy każdym requeście i chce trzymać spójny stan w pamięci. Wyobraź sobie że na "stan" składa sie nie tylko to co w bazie (bo to nie CRUD) ale też jakieś dane płynące z innych serwisów, więc "ładowanie od zera" jest ciężką operacją i nie chce jej robić co request.

jak jedna instalacja przejedzie je logiką to potem można jest wysłać w świat

To jest szczegół, ale websocket jest przecież połączony do konkretnej instancji więc nie da się mu nic wysłać w inny sposób niż z tejże instancji :) Plus jw. każda instancja musi sobie te zmiany "zaaplikować".

Tak na mój prosty rozum to by się przydała jakaś kolejka - jedna instancja przerabia dane pakuje w kolejkę a reszta odczytuje. Do tego DB zapisywacz - który tez jest zapięty na kolejkę.

Raczej event stream niż kolejka ;) No i to jest to co opisałem jako drugą możliwość, ale wymaga to dołożenia drugiego serwisu który zajmuje się "pisaniem", a tutaj zostawienia tylko "czytania" .


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:5 dni
1

Te dwa flowy są osobne i tak ma być. Najpierw dostajesz command z frontu, młócisz i na końcu wypluwasz eventy opisujące zaaplikowane zmiany, dla innych instancji nie powinno mieć znaczenia, czy będą odtwarzały stan z historii z bazy + historii otrzymanej online od innej instancji, czy tylko z historii z bazy, czy tylko ze snapshotu + aktualizacji od innej instancji.

A jeżeli te dwa flowy coś Ci duplikują, to napisz więcej, co one dokładnie robią, bo pewnie masz problem X Y.

UglyMan
  • Rejestracja:około 6 lat
  • Ostatnio:około 3 lata
  • Postów:2206
2
Shalom napisał(a):

Ja tu nie mówie o walidacji, albo nie tylko o walidacji, ale po prostu o "wykonaniu akcji". Tzn. user zmienia jakiśtam tryb działania aplikacji, więc chce sobie znaleźć tego usera, jeśli mam go załadowanego w pamięci, i zmienić mu ten tryb, plus wykonać wszystkie operacje które to za sobą pociąga. Tak żeby kolejny request do tej instancji zwracał poprawne wyniki. Pisałem gdzieś wyżej, że chce uniknąć "ładowania od zera" przy każdym requeście i chce trzymać spójny stan w pamięci. Wyobraź sobie że na "stan" składa sie nie tylko to co w bazie (bo to nie CRUD) ale też jakieś dane płynące z innych serwisów, więc "ładowanie od zera" jest ciężką operacją i nie chce jej robić co request.

Czyli tak naprawdę chodzi o współdzielenie/ustalanie wspólnego stanu (całego lub jego części) aplikacji przez wiele instancji. Takie cos można rozwiązać przez bazę w pamięci np przez redisa (jednego globalnego albo per instancja). Jedna instancja robi walidacje itp itd i zmienia stan aplikacji w redisie albo redisach w zależności od implementacji. Raczej spadek wydajności nie będzie znaczny względem trzymania danych w pamięci a będzie można go zmieniać z zewnątrz. Nowa instancja będzie miała skąd pobrać aktualny stan bez odpytywania wszystkich źródeł i będzie można co jakiś czas zapisać taki stan na dysk tak, że w przypadku faila aplikacja, wstając odczyta sobie poprzedni stan z pliku.

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

A jeżeli te dwa flowy coś Ci duplikują, to napisz więcej, co one dokładnie robią, bo pewnie masz problem X Y.

@Afish nie duplikują w sensie kodu, bo wołam tą samą logikę biznesową pod spodem. Nie podoba mi się tylko trochę to że mam dwa różne entry pointy do tej logiki -> jeden to request z frontu a drugi to event od innej instancji.
Stąd pomysł że np. instancja która dostała request mogłaby tylko emitować eventy o zmianiach bo wtedy entry point do logiki domenowej byłby tylko z event handlera, ale to wymagałoby dodatkowego serwisu który czyta te eventy i wprowadza zmiany do bazy :)

@UglyMan to co opisałeś w zasadzie nie różni się niczym od tego co opisałem na początku jako najbardziej oczywiste rozwiązanie, gdzie instancja która dostała request przetwarza go i wprowadza zmiany, a potem informuje innych o zmianach. To czy zmiany pójdą jakimś redisem czy eventem to już szczegół implementacyjny.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:5 dni
3
Shalom napisał(a):

A jeżeli te dwa flowy coś Ci duplikują, to napisz więcej, co one dokładnie robią, bo pewnie masz problem X Y.

@Afish nie duplikują w sensie kodu, bo wołam tą samą logikę biznesową pod spodem. Nie podoba mi się tylko trochę to że mam dwa różne entry pointy do tej logiki -> jeden to request z frontu a drugi to event od innej instancji.

Ta logika nie powinna być taka sama. Request z frontu powinien dostarczyć commanda, event od innej instancji powinien dostarczyć zweryfikowaną informację o sposobie aktualizacji danych. Intuicyjnie request z frontu prosi "przelicz fakturę" a event z innej aplikacji robi "cena faktury ustawiona na 123". Wspominasz, że CQRS może nie przejść, ale moim zdaniem koncepcyjnie powinieneś iść w takie rozdzielenie.

Shalom napisał(a):

Stąd pomysł że np. instancja która dostała request mogłaby tylko emitować eventy o zmianiach bo wtedy entry point do logiki domenowej byłby tylko z event handlera, ale to wymagałoby dodatkowego serwisu który czyta te eventy i wprowadza zmiany do bazy :)

Nie wiem, czy Ty czasem nie masz problemu z race condition. A obecnie aktualizujesz bazę i wysyłasz eventy w jednej transakcji? Jak nie, to w końcu się to sypnie. To się często rozwiązuje wzorcem Outbox, gdzie eventy do wysłania dodajesz do bazy w tej samej transakcji, co modyfikacje biznesowe, a potem jest osobny demon wysyłający wiadomości na szynę/kolejkę. "osobnego serwisu" do czytania eventów i tak raczej nie unikniesz.

edytowany 1x, ostatnio: Afish
katakrowa
  • Rejestracja:około 10 lat
  • Ostatnio:około 2 lata
  • Lokalizacja:Chorzów
  • Postów:1670
1

@Shalom możesz zrobić rysunek tego co opisujesz? Ja z Twoich opisów rozumiem to tak:

kroki:

  1. event z front end do swojej instancji APP z danymi do zmiany.
  2. Instancja sprawsza sensowność danych i jeśli ok to zapisuje je w SQL i idzie dalej else jakieś message dla front-end.
  3. Zapis danych w SQL
  4. Powiadomienie instancji 2, 3, o zmianie i jej rodzaju i wysłanie komunikatu do własnego FE(6) ( np. potwierdzającego zmianę ).

w istancjach 2, 3 relizują sie kroki
5. odczyt danych z bazy
6. wysłanie komunikatów do swoich front-endów

screenshot-20201020123426.png


Projektowanie i programowanie. Hobbystycznie elektronika i audio oszołom.
Shalom
Prawie, bo odczyt danych z bazy przez inne instancje nie jest do niczego potrzebny, skoro instancja zna poprzedni stan i wie jaka zmiana zaszła ;) Niemniej mozna to też tak zrobić, że event tylko informuje "co" się zmieniło, a samą "treść" pobieramy z bazy, więc ok.
katakrowa
Czyli nie ma kroku 5a, 5b + ( odczyty ) bo dane idą w komunikacie (4). Ok tak można. Ale w takim razie "ni uja" nie nie ma pojęcia jak można by to uprościć...
AF
Między 3 a 4 instancja może zdechnąć i po ptakach. Chyba, że robisz 2PC na bazie i kolejce, ale zazwyczaj robi się outbox.
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 12 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4706
2

Przyznaje, że mam słaby dzień żeby się wczytywać, ale dość standardowe podejście to podział command (z serwisu), eventy
Komenda na podstawie stanu ustala jakie eventy zaszły (ale nic nie zmienia) - czyli wynikiem komendy (nie trzeba tego formalizować- to może być normalna funkcja w serwisie) - jest lista eventów.
Dopiero eventy określają perzystowane zmiany - i odpalasz tą samą listę na wszystkich instancjach.

Tu jest pewien myk - bo jeśli komenda ma zwrócić wynik po zmianach... no to trzeba jakoś poczekać aż będzie zrobiona tych eventów aplikacja, a to zwykle jest asynchroniczne.
(stąd podział na Command i Query zwykle się bierze, żeby nie mieć tego problemu).

Ale z drugiej strony, skoro i tak to klientów wysyłasz zmiany asynchronicznie - to akurat tego problemu nie masz.

Patrząc na oryginalny post:

Przepuścić to przez logikę domenową, żeby sprawdzić czy ta operacja w ogóle ma sens

Normalka - wynikiem tej operacji jest lista eventów

Jeśli tak, to potrzebujemy poinformować frontend o zmianie + potrzebujemy zmianę utrwalić w bazie

nie teraz

Jak nie trudno zauważyć, potrzebujemy też jakoś poinformować inne instancje o tym że zaszły zmiany, żeby mogły odpowiednio updatować swój stan oraz poinformować klientów frontendu którzy są do nich wpięci

wysyłamy eventy do wszystkioch instancjI (również do bieżacej)
i podczas przetwarzania tych eventów informujemy klientów o zmianach


jeden i pół terabajta powinno wystarczyć każdemu
edytowany 3x, ostatnio: jarekr000000
Zobacz pozostałe 6 komentarzy
AF
@Shalom: No a co będzie, jak instancja zdechnie po zapisie do bazy?
superdurszlak
Ew. możesz też olać outbox i zrobić to co podsuwa Jarek i inni - command (POST / mutacja) skutkują tylko wysłaniem eventu, stan in-memory instancji updatuje się dopiero jak dostanie event (nieważne, czy to ta sama która odebrała żądanie), gdzieś na boku robisz sink updatujący bazę, do której nawet nie sięgasz dopóki wystarczą delty z eventów ;) w jednym i drugim przypadku jak instancja się przewróci, to w najgorszym przypadku przetworzy event z opóźnieniem, ale unikasz sytuacji gdzie wszystko się trwale rozjedzie
AF
Rozwiązanie z aktualizacją bazy po otrzymaniu eventu sprawia, że każdy POST musi być asynchroniczny. Przy bezpośrednim zapisie do bazy nie jest to potrzebne i troszkę łatwiej zachować spójność danych. Jednocześnie jak mamy asynchroniczny post i walidację dopiero w innym handlerze przy zapisie, to cały POST może przechodzić z minimalną walidacją, a nie wiem, czy to jest pożądane. Za mało konkretów.
Shalom
Trudne to klikanie w kąkuter, trzeba było zostać spawaczem :) Faktycznie gdyby tylko emitować eventy to informacje o tym że dany POST jest niepoprawny też trzeba by odesłać asynchronicznie a to słabe trochę. Chociaż GraphQL to i tak trochę rak jeśli chodzi o informowanie o błędach, bo jeden request może zawierać dużo operacji ;]
superdurszlak
Trudne to klikanie w kąkuter, trzeba było zostać spawaczem szybciej oślepniesz - jak już coś robić, to wydajnie :]
AreQrm
  • Rejestracja:prawie 11 lat
  • Ostatnio:14 dni
  • Lokalizacja:Londyn
  • Postów:873
3

Pewnie nie to chciałeś usłyszeć, ale CQRS i Event Sourcing idealnie się wpasowują w ten problem. Osobne serwisy do obsługi POST (commands) i osobne do obsługi widoków (eventów, powiadamiania frontendu). Dobry event store mogłby pomoc, ale można samo CQRS zastosować i bez event sourcingu. Zauważ że twój opis samego frontendu idealnie się wpasowuje w event sourcing - dostajesz zmiany, a nie całe zmienione obiekty.

Problem tkwi w szczegółach technicznych, tzn wszystkie unhappy pathy, gdzie np udało się zapisać do bazy, ale event nie wyszedł i nie dotarł gdzie trzeba, bo sieć zawiodła, bo serwis został ubity itp itd. (Nawet używając message bus, mógł się zapisać do bazy ale nie dotrzeć do kolejki). I tutaj właśnie Event sourcing i event store są pomocne, bo masz jedno źródło prawdy które jest zawsze poprawne. A widoki najwyżej z opóźnieniem się odświeżą. Dobry event store np Event Store, dużo oferuje 'out of the box' w tym temacie.
Jeżeli to nie wymagająca na tym poziomie spójności danych aplikacja, i w tych.... nieoszukujmy się, niezwykle rzadkich przypadkach przyjmujesz że gdzieś dane się zapodzieją i nie będzie katastrofy promu kosmicznego, to da się to łyknąć na wiarę, że jak się uda zapis do bazy, to uda się wysłać event z updatem. Ale to tylko na słowo honoru będzie działać. (7 fallacy of network computing daje się czasem w kość ;-) ). Wtedy będzie potrzebny pewnie restart serwisu zajmującego się widokami i powinien sobie wszystko odświeżyć, zależy jak to tam u Ciebie działa w tej waszej NSA, CIA, NASA, ESA czy PPPP ;-)

Inne rozwiązanie, to zapis od razu do bazy updatu i osobnego 'eventu' do tabeli w jednej transakcji. Następnie mamy osobny proces (albo osobny serwis) który czyta z tej tabeli eventów 'nowe' i je wysyła na właściwą kolejkę. Jeśli Ci się wydaje, że w tym przypadku poniekąd robisz z bazy kolejkę... to masz rację, ale tylko dzięki temu masz pewność spójności danych. I nie jest to ani fajne ani super wydajne.


edytowany 1x, ostatnio: AreQrm
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)