redlock-py
redlock-py is a Python library that implements the Redis-based distributed lock manager algorithm (Redlock). It provides a mechanism for acquiring and releasing distributed locks across multiple independent Redis instances to ensure mutual exclusion in a distributed system. The library is currently at version 1.0.8, with a relatively low release cadence, as its PyPI project description was last updated in 2016 and the linked GitHub repository in 2021, suggesting a maintenance-level status.
Warnings
- gotcha The underlying Redlock algorithm has been subject to significant academic and practical critique regarding its safety guarantees, particularly concerning system clock skew, long garbage collection pauses, and the absence of fencing tokens. These issues can potentially lead to violations of mutual exclusion under certain failure conditions.
- gotcha redlock-py requires a Redis client library (e.g., `redis-py`) to communicate with Redis. This dependency is not automatically installed with `pip install redlock-py` and must be installed separately.
- gotcha For the Redlock algorithm to provide its intended fault tolerance and mutual exclusion properties, it *must* be configured with multiple independent Redis instances (an odd number like 3 or 5 is common). Using a single Redis instance or a master-replica setup defeats its purpose and can lead to race conditions due to asynchronous replication.
- gotcha redlock-py does not natively implement 'fencing tokens,' which are crucial for preventing 'stale' clients (those that experience a pause and mistakenly believe they still hold a lock after it has expired) from writing to shared resources. This can lead to data corruption.
- gotcha The project exhibits low maintenance activity. The PyPI description was last updated in 2016, and the linked GitHub repository shows the last commit in 2021. This might indicate a lack of ongoing support, bug fixes, or compatibility updates for newer Python or Redis versions.
Install
-
pip install redlock-py redis
Imports
- Redlock
from redlock import Redlock
Quickstart
import os
from redlock import Redlock
import redis
# Configure Redis connection(s)
# For a true Redlock setup, use multiple independent Redis instances.
# For quickstart, a single local instance is shown.
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = int(os.environ.get('REDIS_PORT', 6379))
REDIS_DB = int(os.environ.get('REDIS_DB', 0))
redis_nodes = [
{"host": REDIS_HOST, "port": REDIS_PORT, "db": REDIS_DB}
# For production, add more independent Redis nodes, e.g.:
# {"host": "redis2.example.com", "port": 6379, "db": 0},
# {"host": "redis3.example.com", "port": 6379, "db": 0},
]
# Initialize the Redlock manager
dlm = Redlock(redis_nodes)
resource_name = "my_critical_resource"
lock_validity_time_ms = 5000 # Lock will be valid for 5 seconds
try:
# Acquire the lock using a context manager (recommended)
print(f"Attempting to acquire lock for '{resource_name}'...")
with dlm.lock(resource_name, lock_validity_time_ms) as my_lock:
if my_lock:
print(f"Lock '{resource_name}' acquired! (Validity: {my_lock.validity}ms)")
# Your critical section code goes here
print("Executing critical section...")
# Simulate work
import time
time.sleep(2)
print("Critical section complete.")
else:
print(f"Could not acquire lock for '{resource_name}'. Another process may hold it.")
except redis.exceptions.ConnectionError as e:
print(f"Error connecting to Redis: {e}. Make sure Redis is running.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
print("Finished redlock-py quickstart example.")