Optimistic vs Pessimistic Lock no Ruby on Rails

Marcelo Barreto
todo cartões tech
Published in
4 min readJan 26, 2020
Foto de uma ferrovia na cidade

Por que usar locks?

Os locks são necessários para cenários onde um ou mais usuários poderão modificar um recurso ao mesmo tempo. Para este artigo, iremos falar sobre duas das várias formas de locks existentes. Vamos para elas:

Optimisic Lock

É a forma em que lockamos um recurso, quando digo recurso, digo um registro no banco de dados, assumindo que ao editar este recurso, ele terá o menor nível de conflito caso algum outro usuário ou sessão tenha editado este mesmo recurso ao mesmo tempo. Para o caso do Rails, esse “ao mesmo tempo” pode ser melhor explicado como:

O usuário #1 abriu o formulário de edição de um recurso ao mesmo tempo que o usuário #2. Não necessariamente quer dizer que essa verificação será ao enviarmos essas informações para o servidor através de uma requisição HTTP. O por quê disso?

O Optimistic Lock funciona como uma espécie de versionamento, em que versionamos nosso recurso na tabela do banco de dados. Para uma melhor visualização de como funciona na prática:

Nós precisamos adicionar uma coluna do tipo integer (com default de 1 ou 0) para servir como a coluna de versionamento na tabela do recurso, caso você queira algo de forma mais automática, você poderá adicionar o campo lock_version, isso não é necessariamente obrigatório. Caso você queira chamar de algum outro nome, por exemplo versao_do_lock, basta apenas que você defina isso na sua model através do atributo de classe locking_column. Ficando assim:

class MinhaClasse self.locking_column = :versao_do_lock end

Caso aconteça algum erro na edição do formulário por parte dos usuários, ocorrerá o erro StaleObjectError, que significa que o registro já foi atualizado anteriormente e está “velho”, lembre-se de que você deverá ficar responsável por lidar com este comportamento de erro, precisando colocar um rescue por exemplo.

Depois de colocarmos essa nova coluna em nossa tabela, precisamos adicionar ao nosso formulário um hidden field e liberar o parâmetro no controller.

Este comportamento pode ser desativado da seguinte forma:

class MinhaClasse self.lock_optimistically = false end

Resumindo, o Optimistic Lock é uma opção para quando, por exemplo, os usuários que estarão alterando o recurso têm certo poder de decisão de qual versão seria a “mais atual”. Em casos que os usuários não deveriam ter esse controle, nós temos o Pessimistic Lock.

Pessimistic Lock

Como dito anteriormente, o Pessimistic Lock cai muito bem para casos que geralmente possuem um pouco mais de complexidade e/ou ocorra alguma forma de concorrência. Este lock funciona diretamente do banco, onde ocorre uma row-level locking. Para matar sua curiosidade, o caso padrão que o Rails gera através desse lock é usando o método SQL FOR UPDATE .

Para conseguirmos utilizar este mecanismo, precisamos encadear as chamadas dos métodos ActiveRecord::Base#find e ActiveRecord::QueryMethods#lock para obter a exclusividade da edição do recurso.

Caso você precise usar um lock específico para o banco de dados que está utilizando, você poderá passar a cláusula especificamente da seguinte forma:

Account.lock(“FOR UPDATE NOWAIT”).find(1) Account.lock(“LOCK IN SHARE MODE”).find(2)

Há também o uso do método #lock! para quando você seleciona um registro através do seu ID, e que pode ser até melhor para casos em que você não precisa “lockar” todos os recursos.

account = Account.find(1).lock!

Para uma segurança extra para nosso lock, podemos usar o ActiveRecord::Base.transaction e adicionar nossa atualização do recurso dentro de uma transação no banco de dados, em que caso algum erro ocorra, um ActiveRecord::Rollback ocorrerá desfazendo as alterações que estariam desatualizadas ou atualizadas de forma errônea.

Conclusão

Os locks são um conhecimento que todo desenvolvedor deveria conhecer, é muito bom dominar este tipo de ferramenta. A abordagem dos dois locks são bem simples e de variados casos de uso. É difícil dizer: em caso x use o Optimistic, em caso y use o Pessimistic, depende da experiência do programador conseguir avaliar qual melhor caso de uso dessas duas opções, porém em casos de concorrência o Pessimistic Lock leva uma grande vantagem em consideração ao Optimistic Lock.

Espero que tenha gostado, e até a próxima!

Referências

--

--