Skip to content

Instantly share code, notes, and snippets.

@bluzky
Created September 24, 2021 11:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bluzky/a0e33dfacca18046acf266f0bb3bcc4b to your computer and use it in GitHub Desktop.
Save bluzky/a0e33dfacca18046acf266f0bb3bcc4b to your computer and use it in GitHub Desktop.
Elixir Redis Lock
defmodule Toolkit.RedisLock do
@moduledoc """
Provide mechanism to lock and check locking of a given key.
When set lock on a key, must set expiration time to make sure no lock live forever
"""
@redix_conn :octosells_cache
@doc """
Lock given key for `lock_duration` in second. Default lock duration is 5 minute
This function make sure only one process can acquire lock. We use `INCR` command to guarantee this.
INCR command is atomic so only one `INCR` command rund at a time and it return the value immediately. We do as follows:
- Increase a key by 1
- If result is 1 -> it's the first one who acquire lock
- Return :ok
- If result is not 1 -> some others lock this key
- Return error
- If some other error happens
- Get lock TTL
- If lock TTL not set
+ Clear lock
- Else
+ do nothing
"""
def acquire(key, duration \\ 300)
def acquire(key, lock_duration) when is_binary(key) and lock_duration > 0 do
with {:ok, 1} <- command(["INCR", key]),
{:ok, _} <- command(["EXPIRE", key, lock_duration]) do
:ok
else
{:ok, _val} ->
{:error, "lock for #{key} has been acquired"}
error ->
# If error happens
# GET TTL of key
case command(["TTL", key]) do
# if no TTL set for lockey then remove the key to avoid locking forever
{:ok, -1} -> command(["DEL", key])
# do nothing
_ -> nil
end
error
end
end
def acquire(key, lock_duration) do
{:error, "lock_key or lock_duration is invalid::#{inspect([key, lock_duration])}}"}
end
@doc """
Clear lock key
"""
def release(key) do
case command(["DEL", key]) do
{:error, _} = error -> error
_ -> :ok
end
end
# shorten command
defp command(args) do
Redix.command(@redix_conn, args)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment