Estou criando um aplicativo de desktop que persiste os dados na nuvem. Uma preocupação que tenho é começar a editar um item no aplicativo e deixá-lo por um tempo, fazendo com que os dados fiquem obsoletos. Obviamente, isso também pode acontecer se duas pessoas tentarem editar o mesmo item ao mesmo tempo. Quando eles terminam a edição e desejam salvar os dados, eu precisaria sobrescrever o que existe atualmente no banco de dados ou verificar se eles começaram a editar após a última alteração e forçá-los a descartar as alterações ou talvez dar a opção de arriscar substituindo as alterações de outra pessoa.
Pensei em adicionar um campo is_locked
e lock_timestamp
na tabela DB. Quando um usuário começa a editar o item, a linha muda is_locked
para true e define o registro de data e hora do bloqueio para o horário atual. Eu teria então uma quantidade de tempo durante a qual a trava é mantida (por exemplo, 5 minutos). Se alguém tentar editar o item, receberá uma mensagem informando que o item está bloqueado e quando o bloqueio expira automaticamente. Se o usuário se afastar durante a edição da trava expirará automaticamente após um período relativamente curto e, uma vez feito, o usuário será avisado de que a trava expirou e será forçado a reiniciar a edição após a atualização dos dados.
Esse seria um bom método para evitar a substituição de dados obsoletos? É um exagero (não espero que o aplicativo seja usado por mais de algumas pessoas simultaneamente em uma única conta).
(Outra preocupação que tenho são duas pessoas que travam o mesmo item, mas acredito que essa é uma condição de corrida com a qual me sinto confortável.)
fonte
Respostas:
Uma coisa que irá ajudá-lo aqui é a terminologia. O que você está descrevendo aqui é chamado de 'bloqueio pessimista'. A principal alternativa a essa abordagem é o 'bloqueio otimista'. No bloqueio pessimista, cada ator deve bloquear o registro antes de atualizá-lo e liberar o bloqueio quando a atualização estiver concluída. No bloqueio otimista, você assume que ninguém mais está atualizando o registro e tentando. A atualização falha se o registro foi alterado por algum outro ator.
Geralmente, o bloqueio otimista é preferível se a chance de dois atores atualizarem a mesma coisa ao mesmo tempo for baixa. O pessimista geralmente é usado quando essa chance é alta ou você precisa saber que sua atualização será bem-sucedida antes do início. Na minha experiência, o bloqueio otimista é quase sempre preferível, porque há muitos problemas inerentes ao bloqueio pessimista. Um dos maiores problemas foi abordado na sua pergunta. Os usuários podem bloquear um registro para edição e depois sair para o almoço. Sua mitigação ajudará nisso, mas a experiência do usuário não será melhor que a abordagem otimista e provavelmente será muito pior. Por exemplo, um usuário abre um registro, começa a atualizá-lo e seu chefe aparece em sua mesa. Outro usuário tenta editar o registro. Está trancado. O segundo usuário continua tentando e, após 5 minutos, o bloqueio expira e o segundo usuário atualiza o registro. O primeiro usuário volta à tela, tenta salvar e é avisado que perdeu o bloqueio. Agora, no mesmo cenário, com tudo a mesma coisa, exceto com o bloqueio otimista, a experiência do primeiro usuário é praticamente a mesma, mas o segundo usuário não espera 5 minutos.
O esquema que você apresentou seria muito melhorado com a implementação de bloqueio otimista para o valor de bloqueio, mas meu palpite é que o bloqueio otimista provavelmente é bom para a coisa toda e você pode se livrar do campo is_locked.
Você não fornece o 'banco de dados em nuvem' que está usando. Você provavelmente deve examinar os recursos para verificar se há recursos internos para isso antes de implementar sua própria solução.
Aqui está a receita básica: em vez de um campo is_locked, tenha um campo de número de versão. Quando você recupera o registro, você extrai a versão atual do registro. Quando você atualiza, a atualização depende do campo da versão que corresponde ao que você recuperou e o incrementa com êxito. Se a versão não corresponder, a atualização não terá efeito e você a reportará como uma falha.
fonte
A partir da resposta de @ JimmyJames , podemos ver como a pergunta é realmente sobre a experiência do usuário .
Tudo depende do contexto. Quanto tempo e esforço são necessários para atualizar um registro? Com que frequência vários usuários desejam atualizar o mesmo documento?
Por exemplo, se seus usuários normalmente levam alguns segundos para atualizar o registro e há pouca disputa, provavelmente o bloqueio otimista é o caminho a percorrer. Na pior das hipóteses, um usuário terá que gastar mais alguns segundos, talvez até um minuto, para atualizar um documento.
Se o seu documento é altamente controverso, mas bem estruturado, talvez você possa permitir que eles bloqueiem campos individuais em incrementos de 30 segundos, mostrando um cronômetro ou uma notificação discreta para permitir que eles estendam o bloqueio.
No entanto, se seus usuários gastam uma quantidade considerável de tempo ou esforço, considere outras abordagens. Seu registro está bem estruturado? Você poderia mostrar aos usuários uma comparação (uma diferença) entre a versão no servidor e a versão que eles estão tentando salvar? Você pode destacar as diferenças? Você pode deixá-los fundir as mudanças? Pense na experiência que você deseja ter com suas ferramentas de controle de origem. Você realmente não quer ser forçado a escrever todo esse código novamente!
Você pode consultar o Google Docs para obter inspiração adicional. Talvez você possa mostrar aos usuários uma notificação de que uma nova versão foi salva. Talvez você possa mostrar a eles quantas pessoas têm o registro aberto, para que possam optar por voltar em um momento menos controverso.
fonte