RedMutex behaviour (RedMutex v0.3.0) View Source

Hex.pm Version CI Coverage Status

RedMutex defines an easy to use interface to control an distributed lock backed by redis.

Usage

When used, the mutex expects the :otp_app as option. The :otp_app should point to an OTP application that has the mutex configuration. For example, the mutex:

defmodule MyApp.MyMutex do
  use RedMutex, otp_app: :my_app
end

Could be configured with:

config :my_app, MyApp.MyMutex,
  url: "redis://localhost:6379",
  key: "red_mutex_lock",
  expiration_in_seconds: 3_600

Options:

  • :url - the redis url. Required.
  • :key- The key at redis used to store the lock information. Defaults to "red_mutex_lock".
  • :expiration_in_seconds - Time in seconds that the resource will be kept locked. After that time the lock will be automattically released. Defaults to 3600, one hour.

Example

# In your config/config.exs file
config :my_app, MyApp.MyMutex,
  url: "redis://localhost:6379",
  key: "red_mutex_lock",
  expiration_in_seconds: 3_600

# In your application code
defmodule MyApp.MyMutex do
  use RedMutex, otp_app: :my_app
end

defmodule MyApp do
  import RedMutex, only: [synchronize: 1]
  alias MyApp.MyMutex

  def syncronized_work do
    synchronize({__MODULE__, :work, []})
  end

  def lock_unlock do
    case MyMutex.acquire_lock() do
      {:ok, lock} ->
        work()
        MyMutex.release_lock(lock)

      {:error, reason} -> {:error, reason}
    end
  end

  def work do
    # do some work
    {:ok, "completed"}
  end
end

Link to this section Summary

Callbacks

Attempts to acquire an lock.

Checks if an lock exists. Returns {:ok, true} if the resource is locked.

Releases the lock.

Obtains an lock, run the callback, and releases the lock when the block completes.

Link to this section Types

Specs

callback() ::
  (... -> any()) | {module :: atom(), function_name :: atom(), args :: [any()]}

Specs

lock() :: String.t()

Specs

reason() :: any()

Link to this section Callbacks

Specs

acquire_lock() :: {:ok, lock()} | {:error, :already_locked} | {:error, reason()}

Attempts to acquire an lock.

Examples

iex> MyMutex.acquire_lock()
{:ok, lock}
iex> MyMutex.acquire_lock()
{:error, :already_locked}
iex> MyMutex.acquire_lock()
{:error, reason}

Specs

exists_lock() :: {:ok, boolean()} | {:error, reason()}

Checks if an lock exists. Returns {:ok, true} if the resource is locked.

Examples

iex> MyMutex.exists_lock()
{:ok, true}
iex> MyMutex.exists_lock()
{:ok, false}
iex> MyMutex.exists_lock()
{:error, reason}

Specs

release_lock(lock()) :: :ok | {:error, reason()}

Releases the lock.

Examples

iex> MyMutex.release_lock(lock)
:ok
iex> MyMutex.release_lock(lock)
{:error, :unlock_fail}
iex> MyMutex.release_lock(lock)
{:error, reason}

Specs

synchronize(callback()) :: any()

Obtains an lock, run the callback, and releases the lock when the block completes.

Examples

iex> MyMutex.synchronize(fn ->
...>   # work
...>   {:ok, "completed"}
...> end)
{:ok, "completed"}
iex> MyMutex.synchronize({MyApp, :work, []})
{:ok, "completed"}