Estoy creando una aplicación de escritorio que persiste los datos en la nube. Una de las preocupaciones que tengo es comenzar a editar un elemento en la aplicación y dejarlo por un tiempo haciendo que los datos se vuelvan obsoletos. Obviamente, esto también puede suceder si 2 personas intentan editar el mismo elemento al mismo tiempo. Cuando terminen su edición y quieran guardar los datos, necesitaría sobrescribir lo que existe actualmente en la base de datos o verificar que comenzaron a editar después del último cambio y forzarlos a descartar sus cambios o quizás darles la opción de arriesgarse sobrescribir los cambios de otra persona.
Pensé en agregar campos is_locked
y lock_timestamp
en la tabla DB. Cuando un usuario comienza a editar el elemento, la fila cambiará is_locked
a verdadero y establecerá la marca de tiempo de bloqueo a la hora actual. Entonces tendría algo de tiempo durante el cual se mantiene el bloqueo (por ejemplo, 5 minutos). Si alguien más intenta editar el elemento, recibirá un mensaje que dice que el elemento está bloqueado y cuando el bloqueo caduca automáticamente. Si el usuario se retira mientras edita, el bloqueo expirará automáticamente después de un período de tiempo relativamente corto y una vez que lo haga, se le advertirá al usuario que el bloqueo ha expirado y se verá obligado a reiniciar la edición después de que se actualicen los datos.
¿Sería este un buen método para evitar sobrescribir datos obsoletos? Es excesivo (no espero que la aplicación sea utilizada por más de unas pocas personas al mismo tiempo en una sola cuenta).
(Otra preocupación que tengo es que 2 personas obtengan un candado para el mismo artículo, sin embargo, creo que es una condición de carrera con la que me siento cómodo).
fuente
Respuestas:
Una cosa que te ayudará aquí es la terminología. Lo que estás describiendo aquí se llama 'bloqueo pesimista'. La principal alternativa a este enfoque es el 'bloqueo optimista'. En el bloqueo pesimista, cada actor debe bloquear el registro antes de actualizarlo y liberar el bloqueo cuando se complete la actualización. En el bloqueo optimista, asume que nadie más está actualizando el registro y lo intenta. La actualización falla si el registro fue cambiado por algún otro actor.
El bloqueo optimista generalmente es preferible si la posibilidad de que dos actores actualicen la misma cosa al mismo tiempo es baja. Pesimista se usa generalmente cuando la probabilidad es alta o si necesita saber que su actualización podrá tener éxito antes de comenzar. En mi experiencia, el bloqueo optimista es casi siempre preferible porque hay muchos problemas inherentes al bloqueo pesimista. Una de las cuestiones más importantes se aborda en su pregunta. Los usuarios pueden bloquear un registro para editarlo y luego irse a almorzar. Su mitigación ayudará con eso, pero la experiencia del usuario no será mejor que el enfoque optimista y es probable que sea mucho peor. Por ejemplo, un usuario abre un registro, comienza a actualizarlo y su jefe aparece en su escritorio. Otro usuario intenta editar el registro. Está cerrada. El segundo usuario sigue intentando y después de 5 minutos, el bloqueo caduca y el segundo usuario actualiza el registro. El primer usuario vuelve a la pantalla, intenta guardar y se le dice que perdió su bloqueo. Ahora, en el mismo escenario con todo igual, excepto el uso de un bloqueo optimista, la experiencia del primer usuario es prácticamente la misma, pero el segundo usuario no espera 5 minutos.
El esquema que diseñe mejoraría enormemente implementando un bloqueo optimista para el valor de bloqueo, pero mi presentimiento es que el bloqueo optimista probablemente esté bien para todo y puede deshacerse del campo is_locked.
No proporciona qué 'base de datos en la nube' está utilizando. Probablemente debería examinar las características de eso para ver si hay características integradas para esto antes de implementar su propia solución.
Aquí está la receta básica: en lugar de un campo is_locked, tenga un campo de número de versión. Cuando recupera el registro, extrae la versión actual del registro. Cuando actualiza, hace que la actualización dependa del campo de versión que coincida con lo que recuperó y lo incremente en caso de éxito. Si la versión no coincide, la actualización no tiene efecto y usted la informa como un error.
fuente
De la respuesta de @ JimmyJames , podemos ver cómo la pregunta es realmente sobre la experiencia del usuario .
Todo depende del contexto. ¿Cuánto tiempo y esfuerzo lleva actualizar un registro? ¿Con qué frecuencia desean varios usuarios actualizar el mismo documento?
Por ejemplo, si sus usuarios suelen tardar unos segundos en actualizar el registro y hay poca contención, entonces el bloqueo optimista es probablemente el camino a seguir. En el peor de los casos, un usuario tendrá que pasar unos segundos más, tal vez hasta un minuto, para actualizar un documento.
Si su documento es muy polémico pero bien estructurado, tal vez pueda permitirles bloquear campos individuales en incrementos de 30 segundos, mostrando un temporizador o una notificación discreta para permitirles extender el bloqueo.
Sin embargo, si sus usuarios pasan una cantidad considerable de tiempo o esfuerzo, entonces debería considerar otros enfoques. ¿Su registro está bien estructurado? ¿Podría mostrar a los usuarios una comparación (una diferencia) entre la versión en el servidor y la versión que están tratando de guardar? ¿Puedes resaltar las diferencias? ¿Puedes dejar que fusionen los cambios? Piense en la experiencia que desea tener con sus herramientas de control de código fuente. ¡Realmente no quieres ser forzado a escribir todo ese código nuevamente!
Puede consultar Google Docs para obtener inspiración adicional. Quizás pueda mostrar a los usuarios una notificación de que se ha guardado una nueva versión. Quizás pueda mostrarles cuántas personas tienen abierto el registro para que puedan elegir regresar en un momento menos polémico.
fuente