RedisCluster.Lock (redis_cluster v0.8.0)

View Source

A simple in-memory locking mechanism using Erlang's :persistent_term.

This module provides a lightweight, process-independent locking mechanism that can be used to coordinate access to shared resources.

Examples

# Create a lock with name :my_lock
iex> RedisCluster.Lock.create(:my_lock)
:ok
iex> RedisCluster.Lock.check(:my_lock)
:ok

# Lock it to prevent concurrent access
iex> RedisCluster.Lock.lock(:my_lock)
:ok
iex> RedisCluster.Lock.check(:my_lock)
:locked

# Unlock it when done
iex> RedisCluster.Lock.unlock(:my_lock)
:ok
iex> RedisCluster.Lock.check(:my_lock)
:ok

# Use with_lock to automatically unlock after an operation
iex> RedisCluster.Lock.with_lock(:auto_lock, fn ->
...>   # This code runs while the lock is held
...>   "operation result"
...> end)
"operation result"
iex> RedisCluster.Lock.check(:auto_lock)
:ok

# Delete a lock when no longer needed
iex> RedisCluster.Lock.create(:temp_lock)
:ok
iex> RedisCluster.Lock.delete(:temp_lock)
true

Summary

Types

The name of the lock as an atom. Must be unique within the application.

Possible statuses of a lock.

Functions

Checks the status of a lock.

Retries a function until the lock becomes available or max attempts are reached.

Creates a new lock with the given name.

Deletes a lock with the given name.

Locks a lock, to signal to other processes that the lock is held.

Unlocks a lock, to signal to other processes that the lock is available.

Executes a function with a lock held, and automatically unlocks when done.

Types

name()

@type name() :: atom()

The name of the lock as an atom. Must be unique within the application.

status()

@type status() :: :ok | :locked

Possible statuses of a lock.

Functions

check(name, default \\ :locked)

@spec check(name(), status()) :: status()

Checks the status of a lock.

Returns :ok if the lock is available, :locked if it's held, or the default value if the lock doesn't exist.

Examples

iex> RedisCluster.Lock.create(:check_lock)
:ok
iex> RedisCluster.Lock.check(:check_lock)
:ok
iex> RedisCluster.Lock.lock(:check_lock)
:ok
iex> RedisCluster.Lock.check(:check_lock)
:locked
iex> RedisCluster.Lock.check(:bogus, :not_found)
:not_found

check_with_retry(name, retries, fun)

@spec check_with_retry(name(), pos_integer(), (status() -> term())) :: term()

Retries a function until the lock becomes available or max attempts are reached.

Returns the result of calling the function with the lock status.

Examples

iex> RedisCluster.Lock.create(:retry_example)
:ok
iex> RedisCluster.Lock.check_with_retry(:retry_example, 3, fn status ->
...>   # This will be called with status = :ok since the lock is available
...>   {:got_status, status}
...> end)
{:got_status, :ok}

create(name)

@spec create(name()) :: :ok

Creates a new lock with the given name.

The lock is initially unlocked.

Examples

iex> RedisCluster.Lock.create(:example_lock)
:ok
iex> RedisCluster.Lock.check(:example_lock)
:ok

delete(name)

@spec delete(name()) :: boolean()

Deletes a lock with the given name.

Returns true if the lock was deleted, false otherwise.

Examples

iex> RedisCluster.Lock.create(:delete_me)
:ok
iex> RedisCluster.Lock.delete(:delete_me)
true

iex> RedisCluster.Lock.delete(:bogus)
false

lock(name)

@spec lock(name()) :: :ok

Locks a lock, to signal to other processes that the lock is held.

Examples

iex> RedisCluster.Lock.create(:lock_me)
:ok
iex> RedisCluster.Lock.lock(:lock_me)
:ok
iex> RedisCluster.Lock.check(:lock_me)
:locked

unlock(name)

@spec unlock(name()) :: :ok

Unlocks a lock, to signal to other processes that the lock is available.

Examples

iex> RedisCluster.Lock.create(:unlock_me)
iex> RedisCluster.Lock.lock(:unlock_me)
iex> RedisCluster.Lock.check(:unlock_me)
:locked
iex> RedisCluster.Lock.unlock(:unlock_me)
iex> RedisCluster.Lock.check(:unlock_me)
:ok

with_lock(name, fun)

@spec with_lock(name(), (-> term())) :: term()

Executes a function with a lock held, and automatically unlocks when done.

This ensures that the lock is released even if the function raises an exception.

Examples

iex> RedisCluster.Lock.with_lock(:protected_operation, fn ->
...>   # Critical section that requires exclusive access
...>   :operation_complete
...> end)
:operation_complete