Mam następujący scenariusz:
- Użytkownik wysyła żądanie GET
/projects/1
i otrzymuje znacznik ETag . - Użytkownik wysyła żądanie PUT do
/projects/1
ETag z kroku # 1. - Użytkownik
/projects/1
przesyła kolejne żądanie PUT do ETag z kroku # 1.
Zwykle drugie żądanie PUT otrzymałoby odpowiedź 412, ponieważ ETag jest teraz nieaktualny - pierwsze żądanie PUT zmodyfikowało zasób, więc ETag już się nie zgadza.
Ale co, jeśli dwa żądania PUT zostaną wysłane w tym samym czasie (lub dokładnie jedno po drugim)? Pierwsze żądanie PUT nie ma czasu na przetworzenie i aktualizację zasobu przed przybyciem PUT nr 2, co powoduje zastąpienie PUT nr 1 przez PUT nr 2. Cały sens optymistycznego blokowania polega na tym, aby tak się nie stało ...
rest
language-agnostic
concurrency
http
maximedupre
źródło
źródło
Odpowiedzi:
Mechanizm ETag określa tylko protokół komunikacyjny dla optymistycznego blokowania. Usługa aplikacji jest odpowiedzialna za wdrożenie mechanizmu wykrywania równoczesnych aktualizacji w celu wymuszenia optymistycznej blokady.
W typowej aplikacji korzystającej z bazy danych zwykle robisz to, otwierając transakcję podczas przetwarzania żądania PUT. Zwykle odczytujesz istniejący stan bazy danych w tej transakcji (aby uzyskać blokadę odczytu), sprawdzasz ważność Etag i zastępujesz dane (w sposób, który spowoduje konflikt zapisu, gdy dojdzie do jakiejkolwiek niezgodnej transakcji równoległej), następnie popełnij. Jeśli poprawnie skonfigurujesz transakcję, jeden z zatwierdzeń powinien zakończyć się niepowodzeniem, ponieważ oba będą próbowały jednocześnie aktualizować te same dane. Będziesz wtedy mógł użyć tej niepowodzenia transakcji, aby zwrócić 412 lub ponowić żądanie, jeśli ma to sens dla aplikacji.
źródło
AND ETag = ...
swojegoUPDATE
oświadczeniaWHERE
i sprawdzając później zaktualizowaną liczbę wierszy. (Lub stosując bardziej rygorystyczny poziom izolacji transakcji, ale tak naprawdę nie polecam.)Musisz wykonać atomowo następującą parę:
Inni nazywają to transakcją - ale zasadniczo atomowe wykonanie tych dwóch operacji uniemożliwia zastąpienie drugiej przypadkowym przypadkiem; bez tego masz wyścig, jak zauważasz.
Jest to nadal uważane za optymistyczne blokowanie, jeśli spojrzysz na duży obraz: że sam zasób nie jest blokowany przez początkowy odczyt (GET) przez dowolnego użytkownika lub użytkowników, którzy patrzą na dane, czy to z zamiarem aktualizacji, czy nie.
Niektóre zachowania atomowe są konieczne, ale dzieje się to w ramach pojedynczego żądania (PUT), a nie próby zablokowania wielu interakcji sieciowych; jest to optymistyczne blokowanie: obiekt nie jest blokowany przez GET, ale nadal można go bezpiecznie zaktualizować za pomocą PUT.
Istnieje również wiele sposobów na atomowe wykonanie tych dwóch operacji - zablokowanie zasobu nie jest jedyną opcją; na przykład może wystarczyć lekka blokada wątku lub obiektu i zależy ona od architektury aplikacji i kontekstu wykonania.
źródło
Twórca aplikacji musi sprawdzić E-Tag i podać tę logikę. Nie jest magią, że serwer WWW robi to za Ciebie, ponieważ wie tylko, jak obliczyć
E-Tag
nagłówki dla zawartości statycznej. Weźmy więc powyższy scenariusz i opiszmy, jak powinna wyglądać interakcja.Serwer otrzymuje żądanie, określa E-Tag dla tej wersji rekordu, zwracając go wraz z faktyczną zawartością.
Ponieważ klient ma teraz wartość E-Tag, może to uwzględnić w
PUT
żądaniu:W tym momencie aplikacja musi wykonać następujące czynności:
Wyślij odpowiedź powodzenia.
Jeśli nadejdzie inne żądanie i spróbuje wykonać
PUT
podobne do powyższego, za drugim razem, gdy kod serwera je oceni, będziesz odpowiedzialny za przesłanie komunikatu o błędzie.W przypadku awarii wyślij odpowiedź awarii.
To jest kod, który musisz napisać. E-Tag może w rzeczywistości być dowolnym tekstem (w granicach określonych w specyfikacji HTTP). To nie musi być liczba. Może to być również wartość skrótu.
źródło
Jako uzupełnienie innych odpowiedzi opublikuję jeden z najlepszych cytatów w dokumentacji ZeroMQ, który wiernie opisuje podstawowy problem:
źródło