Python Redis Lock
python-redis-lock is a Python library that provides a distributed lock context manager, implemented using Redis's `SETNX` (SET if Not eXists) and `BLPOP` operations. It aims to offer an interface similar to Python's built-in `threading.Lock`. The current version is 4.0.1, and it maintains an active release cadence, with its latest major update in late 2022.
Warnings
- breaking Version 4.0.0 dropped support for Python 2.7 and Python 3.6. Users on these older Python versions must use `python-redis-lock < 4.0.0`.
- gotcha If an application crashes while holding a lock and `expire` (timeout) is not set, the lock may remain in Redis indefinitely, causing permanent deadlocks. Setting `expire` alone will release the lock after a fixed duration, but if the critical section takes longer, the lock might be released prematurely.
- deprecated The `force` parameter on the `release()` method was removed in version 3.0.0. This option was considered to encourage sloppy programming and is no longer available.
- gotcha `python-redis-lock` implements a distributed lock based on Redis's `SETNX` and `BLPOP`. It is *not* an implementation of the more complex Redlock algorithm (which involves multiple independent Redis instances for higher fault tolerance).
Install
-
pip install python-redis-lock
Imports
- Lock
from redis_lock import Lock
Quickstart
import redis
import time
import os
from redis_lock import Lock
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = int(os.environ.get('REDIS_PORT', 6379))
# Connect to Redis
client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, db=0)
lock_name = "my-distributed-lock"
# Acquire a lock using a context manager, with a 10-second expiration
# and automatic renewal while the 'with' block is active.
print(f"Attempting to acquire lock '{lock_name}'...")
with Lock(client, lock_name, expire=10, auto_renewal=True, blocking_timeout=5) as lock:
if lock.acquired:
print(f"Lock '{lock_name}' acquired! Doing some critical work...")
# Simulate work that takes longer than the expire time
# auto_renewal will keep the lock alive.
time.sleep(15)
print(f"Work finished. Lock '{lock_name}' will be automatically released.")
else:
print(f"Failed to acquire lock '{lock_name}'. Another process holds it.")
# You can also check if a lock is currently held (by anyone)
if Lock(client, lock_name).locked():
print(f"Lock '{lock_name}' is currently held by someone else (or was not properly released).")
else:
print(f"Lock '{lock_name}' is not currently held.")
client.close()