Packages

Redlock (Redis Distributed Lock) implementation

Current section

Files

Jump to
red_mutex lib red_mutex command.ex
Raw

lib/red_mutex/command.ex

defmodule RedMutex.Command do
@moduledoc false
@helper_script ~S"""
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
"""
@helper_hash :sha |> :crypto.hash(@helper_script) |> Base.encode16(case: :lower)
def acquire_lock(conn, key, expiration_in_seconds)
when is_atom(conn) and is_binary(key) and is_integer(expiration_in_seconds) do
lock = gen_mutex()
case Redix.command(conn, ["SET", key, lock, "NX", "EX", expiration_in_seconds]) do
{:ok, "OK"} -> {:ok, lock}
{:ok, nil} -> {:error, :already_locked}
{:error, reason} -> {:error, reason}
end
end
def release_lock(conn, key, lock) when is_atom(conn) and is_binary(key) and is_binary(lock) do
case Redix.command(conn, ["EVALSHA", @helper_hash, "1", key, lock]) do
{:ok, 1} -> :ok
{:ok, 0} -> {:error, :unlock_fail}
{:error, reason} -> {:error, reason}
end
end
def load_script!(conn) do
@helper_hash = Redix.command!(conn, ["SCRIPT", "LOAD", @helper_script])
end
def exists_lock(conn, key) do
case Redix.command(conn, ["EXISTS", key]) do
{:ok, 1} -> {:ok, true}
{:ok, 0} -> {:ok, false}
{:error, reason} -> {:error, reason}
end
end
defp gen_mutex do
:sha256
|> :crypto.hash(:crypto.strong_rand_bytes(32))
|> Base.encode64()
end
end