Aktywne Wpisy
yosemitesam +26
kamilek123 +303
Cześć. Jestem już po operacji tego guza.
Chwilę po 7 przyszły do mnie 3 młode dziewczyny, które zaprowadziły mnie na blok operacyjny. Ok 7.35 leżałem już na sali i były ze mną 3 osoby z anestezjologia, które mnie uśpiły. Obudziłem się na sali po operacyjnej, ale nie wiem kiedy bo byłem tak naćpany jeszcze i zaraz zasnąłem. Ok 14 już obudziłem się na moim łóżku w moje sali. Dosłownie zaraz przyszli rodzice,
Chwilę po 7 przyszły do mnie 3 młode dziewczyny, które zaprowadziły mnie na blok operacyjny. Ok 7.35 leżałem już na sali i były ze mną 3 osoby z anestezjologia, które mnie uśpiły. Obudziłem się na sali po operacyjnej, ale nie wiem kiedy bo byłem tak naćpany jeszcze i zaraz zasnąłem. Ok 14 już obudziłem się na moim łóżku w moje sali. Dosłownie zaraz przyszli rodzice,
poproszę o gotowe rozwiązanie albo link do materiału z którego mógłbym skorzystać. Mam następujący problem:
Jest aplikacja napisana w #php #symfony która to publikuje eventy w kolejce #rabbitmq. Są też 2 consumery, które to konsumują te eventy. Problem jest taki, że w pewnym miejscu mam race condition. Są opublikowane rożne eventy, które podczas konsumpcji tworzą lub aktualizują rekord w bazie danych. Problem jest w tym, że konsumpcja może nastąpić w bardzo krótkim czasie przez co 2 consumery będą próbowały stworzyć rekord w bazie danych. Dodałem kod, który sprawdza czy rekord istnieje w bazie danych czy nie, a następnie rzucam wyjątek, żeby wykonała się aktualizacja rekordu, ale czasami różnice są takie minimalne, że tego nie wystarcza.
Poproszę o odpowiedź inną niż - zostaw sobie jednego consumera i problem rozwiązany - to nie zadziała, bo czasami ktoś chce wygenerować ogromny raport, np. za pół roku czy za rok i consumer będzie zablokowany przez cały czas generowania raportu, więc reszta systemu nie będzie działać poprawnie, a z dwoma consumerami można sobie pozwolić na blokadę jednego przez dłuższy czas, ponieważ drugi będzie dalej obsługiwał eventy z kolejki.
Myślałem nad wykorzystaniem cache (redis, memcached czy coś innego) i umieszczenie tam flagi - obsługa tego rekordu jest zablokowana w tym momencie, spróbuj później, ale nie wiem czy takie rzeczy się stosuje czy jest na to lepsze rozwiązanie.
#webdev #programowanie
https://symfony.com/doc/current/components/lock.html
Może sprawdź jeszcze czy nie ograsz tego w middleware.
https://symfony.com/doc/current/messenger.html#middleware-for-doctrine
Dziękuję.
Problem z doctrine jest następujący - błąd
The EntityManager is closed.
Jest to spowodowane błędem po stronie Mysql - dziś wreszcie udało mi się namierzyć co się dzieje.Otóż to wygląda tak:
1. z powodu wyżej opisanej sytuacji pierwszy consumer tworzy rekord w
Na race condition aktualizacji może pomóc transakcja +
SELECT FOR UPDATE
, żeby zrobić locka na wierszu dopóki nie skończysz swojej operacji update'u.Co do race condition przy tworzeniu wierszy, to już musiałbyś dokładnie napisać co
Tutaj jest klasa o której mowa: https://pastebin.com/Z9a7DVB6
dałem tutaj funkcję rekurencyjną, żeby w razie złapania wyjątku kod wykonał się jeszcze raz, ale no tak jak pisałem poprzednio - tego nie wystarcza i nadal mam mnóstwo błędów z powodu EntityManager is
Zamiast tego zrób albo tak jak pisałem - transakcja, select for update, update/insert, koniec transakcji. Albo jeśli jesteś w stanie to zrobić w sposób idempotentny to po prostu
INSERT ... ON DUPLICATE KEY UPDATE
alboREPLACE
.Ewentualnie zapytaj po prostu jakiegoś seniora
nie wiem czy dobrze zrozumialem problem, ale to co mozesz uzyc to UPSERT, a jak musisz cos sprawdzic przed to optimistic locking + retry
overengineering
@mariecziek: Już kilka lat nie siedzę w symfony, ale kiedyś miałem podobny problem. Doctrine po utworzeniu encji i dodaniu jej do em nie zapisuje tego od razu do bazy, ale możesz to wymuśić bodajrze przez flush (czy jakoś tak). To powinno pozwolić zmniejszyć ilość konfliktów w tym miejscu.