1
0
mirror of https://github.com/quay/quay.git synced 2026-01-29 08:42:15 +03:00
Files
quay/util/locking.py
2019-12-02 12:23:08 -05:00

71 lines
2.3 KiB
Python

import logging
from redis import RedisError
from redlock import RedLock, RedLockError
from app import app
logger = logging.getLogger(__name__)
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, "single_connection_client": True}
)
self._lock_ttl = lock_ttl
self._redlock = None
def __enter__(self):
if not self.acquire():
raise LockNotAcquiredException()
def __exit__(self, type, value, traceback):
self.release()
def acquire(self):
logger.debug("Acquiring global lock %s", self._lock_name)
try:
self._redlock = RedLock(
self._lock_name, connection_details=[self._redis_info], ttl=self._lock_ttl
)
acquired = self._redlock.acquire()
if not acquired:
logger.debug("Was unable to not acquire lock %s", self._lock_name)
return False
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
def release(self):
if self._redlock is not None:
logger.debug("Releasing lock %s", self._lock_name)
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