Tengo este siguiente escenario:
- Un usuario realiza una solicitud GET
/projects/1
y recibe un ETag . - El usuario realiza una solicitud PUT
/projects/1
con el ETag desde el paso 1. - El usuario realiza otra solicitud PUT
/projects/1
con el ETag desde el paso 1.
Normalmente, la segunda solicitud PUT recibiría una respuesta 412, ya que el ETag ahora está obsoleto: la primera solicitud PUT modificó el recurso, por lo que el ETag ya no coincide.
Pero, ¿qué pasa si las dos solicitudes PUT se envían al mismo tiempo (o exactamente una después de la otra)? La primera solicitud PUT no tiene tiempo para procesar y actualizar el recurso antes de que llegue PUT # 2, lo que hace que PUT # 2 sobrescriba PUT # 1. El objetivo del bloqueo optimista es que eso no suceda ...
rest
language-agnostic
concurrency
http
maximedupre
fuente
fuente
Respuestas:
El mecanismo ETag especifica solo el protocolo de comunicación para el bloqueo optimista. Es responsabilidad del servicio de aplicación implementar el mecanismo para detectar actualizaciones concurrentes para aplicar el bloqueo optimista.
En una aplicación típica que usa una base de datos, generalmente lo haría abriendo una transacción al procesar una solicitud PUT. Normalmente leería el estado existente de la base de datos dentro de esa transacción (para obtener un bloqueo de lectura), verificaría la validez de su Etag y sobrescribirá los datos (de una manera que provocará un conflicto de escritura cuando haya una transacción concurrente incompatible), entonces comprometerse. Si configura la transacción correctamente, uno de los commits debería fallar porque ambos intentarán actualizar los mismos datos simultáneamente. Luego podrá utilizar este error de transacción para devolver 412 o volver a intentar la solicitud, si tiene sentido para la aplicación.
fuente
AND ETag = ...
enUPDATE
laWHERE
cláusula de su estado de cuenta y verificar el recuento actualizado de filas después. (O mediante el uso de un nivel de aislamiento de transacción más estricto, pero realmente no lo recomiendo.)Tienes que ejecutar el siguiente par atómicamente:
Otros lo llaman una transacción, pero fundamentalmente, la ejecución atómica de estas dos operaciones es lo que impide que una sobrescriba a la otra por accidente; sin esto tienes una condición de carrera, como lo estás notando.
Esto aún se considera un bloqueo optimista, si observa el panorama general: que el recurso en sí no está bloqueado por la lectura inicial (GET) por ningún usuario o cualquier usuario que esté mirando los datos, ya sea con la intención de actualizar o no.
Es necesario algún comportamiento atómico, pero esto ocurre dentro de una sola solicitud (el PUT) en lugar de intentar mantener un bloqueo en múltiples interacciones de red; esto es un bloqueo optimista: el objeto no está bloqueado por GET pero PUT todavía puede actualizarlo de forma segura.
También hay muchas formas de lograr la ejecución atómica de estas dos operaciones: bloquear el recurso no es la única opción; por ejemplo, un hilo ligero o bloqueo de objeto puede ser suficiente y depende de la arquitectura y el contexto de ejecución de su aplicación.
fuente
Está en el desarrollador de la aplicación verificar la etiqueta electrónica y proporcionar esa lógica. No es mágico que el servidor web lo haga por ti porque solo sabe cómo calcular
E-Tag
encabezados para contenido estático. Así que tomemos su escenario anterior y analicemos cómo debería ocurrir la interacción.El servidor recibe la solicitud, determina la etiqueta electrónica para esta versión del registro y la devuelve con el contenido real.
Como el cliente ahora tiene el valor E-Tag, puede incluir eso con la
PUT
solicitud:En este punto, su aplicación debe hacer lo siguiente:
Envía la respuesta de éxito.
Si llega otra solicitud e intenta realizar una
PUT
similar a la solicitud anterior, la segunda vez que su código de servidor la evalúa, usted es responsable de proporcionar el mensaje de error.En caso de falla, envíe la respuesta a la falla.
Este es el código que realmente tienes que escribir. De hecho, la etiqueta E puede ser cualquier texto (dentro de los límites definidos en la especificación HTTP). No tiene que ser un número. También puede ser un valor hash.
fuente
Como complemento a las otras respuestas, publicaré una de las mejores citas en la documentación de ZeroMQ que describe fielmente el problema subyacente:
fuente