Skip to content

Instantly share code, notes, and snippets.

@adewes
Last active December 20, 2015 08:49
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save adewes/6103220 to your computer and use it in GitHub Desktop.
Save adewes/6103220 to your computer and use it in GitHub Desktop.
A Redis-based distributed lock class, based on the solution proposed by Chris Lamb (https://chris-lamb.co.uk/posts/distributing-locking-python-and-redis).
import redis
import time
class LockTimeout(BaseException):
pass
class Lock(object):
"""
Implements a distributed lock using Redis.
"""
def __init__(self, redis, lock_type, key, expires=60, timeout=10):
self.key = key
self.lock_type = lock_type
self.redis = redis
self.timeout = timeout
self.expires = expires
def lock_key(self):
return "%s:locks:%s" % (self.lock_type,self.key)
def __enter__(self):
timeout = self.timeout
while timeout >= 0:
expires = time.time() + self.expires + 1
pipe = self.redis.pipeline()
lock_key = self.lock_key()
pipe.watch(lock_key)
try:
lock_value = float(self.redis.get(lock_key))
except (ValueError,TypeError):
lock_value = None
if not lock_value or lock_value < time.time():
try:
pipe.multi()
pipe.set(lock_key,expires)
pipe.expire(lock_key,self.expires+1)
pipe.execute()
return expires
except redis.WatchError:
print "Someone tinkered with the lock!"
pass
timeout -= 0.01
time.sleep(0.01)
raise LockTimeout("Timeout whilst waiting for lock")
def __exit__(self, exc_type, exc_value, traceback):
self.redis.delete(self.lock_key())
if __name__ == '__main__':
server = redis.Redis("localhost")
with Lock(server,"events","user:abc",expires = 10) as lock:
print "locked"
time.sleep(20)
print "unlocked!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment