J'ai ce scénario suivant:
- Un utilisateur fait une demande GET à
/projects/1
et reçoit un ETag . - L'utilisateur fait une demande PUT
/projects/1
avec l'ETag à partir de l'étape # 1. - L'utilisateur fait une autre demande PUT
/projects/1
avec l'ETag à partir de l'étape # 1.
Normalement, la deuxième demande PUT recevrait une réponse 412, car l'ETag est désormais périmé - la première demande PUT a modifié la ressource, de sorte que l'ETag ne correspond plus.
Mais que se passe-t-il si les deux demandes PUT sont envoyées en même temps (ou exactement l'une après l'autre)? La première demande PUT n'a pas le temps de traiter et de mettre à jour la ressource avant l'arrivée de PUT # 2, ce qui fait que PUT # 2 écrase PUT # 1. Le but du verrouillage optimiste est que cela ne se produise pas ...
rest
language-agnostic
concurrency
http
maximedupre
la source
la source
Réponses:
Le mécanisme ETag spécifie uniquement le protocole de communication pour un verrouillage optimiste. Il incombe au service d'application de mettre en œuvre le mécanisme de détection des mises à jour simultanées pour appliquer le verrouillage optimiste.
Dans une application typique qui utilise une base de données, vous le feriez généralement en ouvrant une transaction lors du traitement d'une demande PUT. Vous devriez normalement lire l'état existant de la base de données à l'intérieur de cette transaction (pour obtenir un verrou de lecture), vérifier votre validité Etag et écraser les données (d'une manière qui provoquera un conflit d'écriture en cas de transaction simultanée incompatible), puis engagez-vous. Si vous configurez la transaction correctement, l'une des validations devrait échouer car elles essaieront toutes les deux de mettre à jour les mêmes données simultanément. Vous pourrez ensuite utiliser cet échec de transaction pour renvoyer 412 ou réessayer la demande, si cela a du sens pour l'application.
la source
AND ETag = ...
dansUPDATE
laWHERE
clause de votre instruction et en vérifiant le nombre de lignes mis à jour par la suite. (Ou en utilisant un niveau d'isolement de transaction plus strict, mais je ne le recommande pas vraiment.)Vous devez exécuter la paire suivante de manière atomique:
D'autres appellent cela une transaction - mais fondamentalement, l'exécution atomique de ces deux opérations est ce qui empêche l'une d'écraser l'autre par accident de timing; sans cela, vous avez une condition de course, comme vous le constatez.
Ceci est toujours considéré comme un verrouillage optimiste, si vous regardez la situation dans son ensemble: que la ressource elle-même n'est pas verrouillée par la lecture initiale (GET) par un utilisateur ou des utilisateurs qui consultent les données, que ce soit avec l'intention de les mettre à jour ou non.
Un certain comportement atomique est nécessaire, mais cela se produit dans une seule demande (le PUT) plutôt que d'essayer de maintenir un verrou sur plusieurs interactions réseau; c'est un verrouillage optimiste: l'objet n'est pas verrouillé par le GET mais peut toujours être mis à jour en toute sécurité par PUT.
Il existe également de nombreuses façons de réaliser l'exécution atomique de ces deux opérations - le verrouillage de la ressource n'est pas la seule option; par exemple, un thread léger ou un verrou d'objet peut suffire et dépend de l'architecture et du contexte d'exécution de votre application.
la source
C'est au développeur de l'application de vérifier le E-Tag et de fournir cette logique. Ce n'est pas magique que le serveur Web fasse pour vous car il ne sait que calculer les en-
E-Tag
têtes pour le contenu statique. Prenons donc votre scénario ci-dessus et décomposons comment l'interaction doit se produire.Le serveur reçoit la demande, détermine le E-Tag pour cette version de l'enregistrement, le renvoyant avec le contenu réel.
Étant donné que le client a maintenant la valeur E-Tag, il peut inclure cela avec la
PUT
demande:À ce stade, votre application doit effectuer les opérations suivantes:
Envoyez la réponse de réussite.
Si une autre demande vient et tente d'effectuer une opération
PUT
similaire à la demande ci-dessus, la deuxième fois que votre code serveur l'évalue, vous êtes responsable de fournir le message d'erreur.En cas d'échec, envoyez la réponse d'échec.
C'est le code que vous devez réellement écrire. Le E-Tag peut en fait être n'importe quel texte (dans les limites définies dans la spécification HTTP). Il n'est pas nécessaire que ce soit un nombre. Il peut également s'agir d'une valeur de hachage.
la source
En complément des autres réponses, je posterai l'une des meilleures citations de la documentation ZeroMQ qui décrit fidèlement le problème sous-jacent:
la source