51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
|
import logging
|
||
|
|
||
|
from redis import ConnectionError
|
||
|
from redlock import RedLock, RedLockError
|
||
|
|
||
|
from app import app
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
class GlobalLock(object):
|
||
|
""" A lock object that blocks globally via Redis. Note that Redis is not considered a tier-1
|
||
|
service, so this lock should not be used for any critical code paths.
|
||
|
"""
|
||
|
def __init__(self, name, lock_ttl=600):
|
||
|
self._lock_name = name
|
||
|
self._redis_info = dict(app.config['USER_EVENTS_REDIS'])
|
||
|
self._redis_info.update({'socket_connect_timeout': 5, 'socket_timeout': 5})
|
||
|
|
||
|
self._lock_ttl = lock_ttl
|
||
|
self._redlock = None
|
||
|
|
||
|
def __enter__(self):
|
||
|
return self.lock()
|
||
|
|
||
|
def __exit__(self ,type, value, traceback):
|
||
|
self.unlock()
|
||
|
|
||
|
def lock(self):
|
||
|
logger.debug('Acquiring global lock %s', self._lock_name)
|
||
|
try:
|
||
|
redlock = RedLock(self._lock_name, connection_details=[self._redis_info],
|
||
|
ttl=self._lock_ttl)
|
||
|
redlock.acquire()
|
||
|
self._redlock = redlock
|
||
|
logger.debug('Acquired lock %s', self._lock_name)
|
||
|
return True
|
||
|
except RedLockError:
|
||
|
logger.debug('Could not acquire lock %s', self._lock_name)
|
||
|
return False
|
||
|
except ConnectionError as ce:
|
||
|
logger.debug('Could not connect to Redis for lock %s: %s', self._lock_name, ce)
|
||
|
return False
|
||
|
|
||
|
|
||
|
def unlock(self):
|
||
|
if self._redlock is not None:
|
||
|
logger.debug('Releasing lock %s', self._lock_name)
|
||
|
self._redlock.release()
|
||
|
logger.debug('Released lock %s', self._lock_name)
|
||
|
self._redlock = None
|