This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/util/locking.py

66 lines
2 KiB
Python
Raw Normal View History

import logging
from redis import RedisError
from redlock import RedLock, RedLockError
from app import app
logger = logging.getLogger(__name__)
2016-08-29 15:28:53 +00:00
class LockNotAcquiredException(Exception):
""" Exception raised if a GlobalLock could not be acquired. """
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):
2016-08-29 15:28:53 +00:00
if not self.acquire():
raise LockNotAcquiredException()
2016-08-29 15:28:53 +00:00
def __exit__(self, type, value, traceback):
self.release()
2016-08-29 15:28:53 +00:00
def acquire(self):
logger.debug('Acquiring global lock %s', self._lock_name)
try:
redlock = RedLock(self._lock_name, connection_details=[self._redis_info],
2016-08-29 15:28:53 +00:00
ttl=self._lock_ttl)
acquired = redlock.acquire()
if not acquired:
logger.debug('Was unable to not acquire lock %s', self._lock_name)
return False
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 RedisError as re:
logger.debug('Could not connect to Redis for lock %s: %s', self._lock_name, re)
return False
2016-08-29 15:28:53 +00:00
def release(self):
if self._redlock is not None:
logger.debug('Releasing lock %s', self._lock_name)
2016-08-29 15:28:53 +00:00
try:
self._redlock.release()
except RedLockError:
logger.debug('Could not release lock %s', self._lock_name)
except RedisError as re:
logger.debug('Could not connect to Redis for releasing lock %s: %s', self._lock_name, re)
logger.debug('Released lock %s', self._lock_name)
self._redlock = None