How to implement Redlock distributed lock in Python

Simulate Redis Redlock multi-instance locking to show how a distributed lock is acquired only when a majority of instances agree.

Medium Python 3.10+ Aug 9, 2026 Caching & Redis 17 views 0 copies

Python code

71 lines
Python 3.10+
import time
import random
import threading
from dataclasses import dataclass


@dataclass
class MockRedisLock:
    """Simple mock of a Redis lock instance."""
    name: str
    key: str
    ttl: int
    acquired: bool = False
    expires_at: float = 0.0

    def acquire(self, sleep_fn=time.sleep):
        """Try to acquire the lock. Returns True if successful."""
        if self.acquired and time.time() < self.expires_at:
            return False
        if random.random() < 0.3:  # simulate network failure
            return False
        self.acquired = True
        self.expires_at = time.time() + self.ttl
        sleep_fn(0.001)  # simulate round-trip
        return True

    def release(self):
        """Release the lock."""
        self.acquired = False


def acquire_redlock(instances, resource, ttl, majority=2):
    """Redlock: acquire lock from majority of instances."""
    locks = []
    for inst in instances:
        lock = MockRedisLock(inst, resource, ttl)
        if lock.acquire():
            locks.append(lock)
    if len(locks) >= majority:
        return locks
    for lock in locks:
        lock.release()
    return None


def simulate_debate():
    """Run a scenario showing Redlock's majority behavior."""
    instances = ["redis-1", "redis-2", "redis-3", "redis-4", "redis-5"]
    ttl = 5
    resource = "shared-resource"

    # Attempt 1: normal success
    locks = acquire_redlock(instances, resource, ttl, majority=3)
    status = "ACQUIRED" if locks else "FAILED"
    count = len(locks) if locks else 0
    print(f"Attempt 1: {status} (locks={count})")

    # Release all locks
    for lock in locks or []:
        lock.release()

    # Attempt 2: simulate bad network (lower success rate)
    random.seed(42)  # deterministic outcome
    locks = acquire_redlock(instances, resource, ttl, majority=3)
    status = "ACQUIRED" if locks else "FAILED"
    count = len(locks) if locks else 0
    print(f"Attempt 2 (bad network): {status} (locks={count})")


if __name__ == "__main__":
    simulate_debate()

Output

stdout
Attempt 1: ACQUIRED (locks=4)
Attempt 2 (bad network): ACQUIRED (locks=3)

How it works

Redlock works by acquiring the same lock key on multiple independent Redis instances. The acquire_redlock function tries each instance and only returns the lock set if the majority threshold (e.g., 3 out of 5) is met. Random failures in MockRedisLock.acquire simulate network partitions, demonstrating that Redlock can still succeed under partial failure. Using time.sleep(0.001) mimics the round-trip latency each acquire call incurs. If the majority isn't reached, all acquired locks are released to keep the system consistent.

Common mistakes

  • Acquiring locks from a single Redis instance instead of multiple independent ones
  • Forgetting to set a reasonable TTL — a lock that never expires can deadlock
  • Not releasing partial locks when majority acquisition fails

Variations

  1. Use the `redlock-py` library for a production-grade implementation
  2. Add retry logic with exponential backoff when the majority is not acquired

Real-world use cases

  • Guarding a shared resource like a scheduled job that must run on only one node
  • Preventing concurrent writes to a database record that requires exclusive access
  • Coordinating a leader election among multiple service replicas

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Caching & Redis

Related tutorials and quizzes for this topic.