Um lock Redis mais eficiente

O Discourse utiliza amplamente o bloqueio (lock) do Redis como mecanismo de sincronização. A implementação do bloqueio do Redis no Discourse (como mostrado abaixo) pode ser aprimorada para usar menos comandos do Redis, reduzindo o tempo de ida e volta (round-trip) e o custo de execução no Redis.

Como podemos aprimorá-lo

Tanto lock quanto unlock utilizam Transações do Redis. O processo de lock poderia ser simplificado para o código abaixo.

WATCH key
GET key # determina se a chave expirou
MULTI
SET key
EXPIRE key, expire_time + 1

A razão para usar Transações do Redis (assumi) parece ser a de verificar se a chave expirou antes de realmente defini-la.

Mas acho que poderíamos simplesmente usar o comando SETEX fornecido pelo Redis, que define uma chave com um tempo de expiração. Na verdade, a Documentação do Redis SETEX o usa como exemplo para substituir SET e EXPIRE por SETEX.

Aqui estão os argumentos para por que devemos substituí-lo:

  1. Definir o valor como tempo de expiração e verificá-lo antes de definir a chave é desnecessário. O mecanismo de TTL é suficiente para garantir que a chave expire corretamente.
  2. Mesmo que decidamos usar o tempo de expiração como valor, não precisamos de nenhuma transação. Como fornecer atomicidade entre o GET (linha 2 no código acima) e MULTI e EXEC não oferece nada. Isso ocorre porque, se o bloqueio não for adquirido, ele será refeito.

Uma nota histórica

Investiguei o histórico de commits do git para obter mais informações. Parece que, quando o bloqueio do Redis foi introduzido, não utilizávamos o TTL fornecido pelo Redis. O recurso de TTL foi introduzido muito depois.

Portanto, acho que podemos dar um passo adiante e remover completamente as Transações do Redis.

Conforme Develop with Redis | Docs

Provavelmente podemos descartar toda a transação e fazer um set com as opções px e nx