From c12654bf46da701cd30dd9995091444bc046cf69 Mon Sep 17 00:00:00 2001 From: Kenny Lee Sin Cheong <2530351+kleesc@users.noreply.github.com> Date: Wed, 14 Apr 2021 14:44:33 -0400 Subject: [PATCH] lock: allows global lock to be used from main app (PROJQUAY-788) (#745) GlobalLock had a dependency on app, which would cause a circular dependency if imported from the main app. Workaround this by requiring to pass the configuration to the GlobalLock instead (this is done by a classmethod, due to the use of Redlock's factory). This means before the use of GlobalLock, "configure" will need to be called once, per process. --- util/locking.py | 33 +++++++++++-------- .../blobuploadcleanupworker.py | 1 + workers/gc/gcworker.py | 1 + workers/globalpromstats/globalpromstats.py | 1 + workers/logrotateworker.py | 1 + workers/namespacegcworker.py | 1 + workers/repositorygcworker.py | 1 + 7 files changed, 25 insertions(+), 14 deletions(-) diff --git a/util/locking.py b/util/locking.py index fdb5002c1..47c7596ea 100644 --- a/util/locking.py +++ b/util/locking.py @@ -3,8 +3,6 @@ import logging from redis import RedisError from redlock import RedLockFactory, RedLockError -from app import app - logger = logging.getLogger(__name__) @@ -14,6 +12,19 @@ class LockNotAcquiredException(Exception): """ +def _redlock_factory(config): + _redis_info = dict(config["USER_EVENTS_REDIS"]) + _redis_info.update( + { + "socket_connect_timeout": 5, + "socket_timeout": 5, + "single_connection_client": True, + } + ) + lock_factory = RedLockFactory(connection_details=[_redis_info]) + return lock_factory + + # TODO(kleesc): GlobalLock should either renew the lock until the caller is done, # or signal that it is no longer valid to the caller. Currently, GlobalLock will # just silently expire the redis key, making the lock available again while any @@ -28,21 +39,15 @@ class GlobalLock(object): lock_factory = None - def __new__(cls, *args, **kwargs): + @classmethod + def configure(cls, config): if cls.lock_factory is None: - _redis_info = dict(app.config["USER_EVENTS_REDIS"]) - _redis_info.update( - { - "socket_connect_timeout": 5, - "socket_timeout": 5, - "single_connection_client": True, - } - ) - - cls.lock_factory = RedLockFactory(connection_details=[_redis_info]) - return super(GlobalLock, cls).__new__(cls, *args, **kwargs) + cls.lock_factory = _redlock_factory(config) def __init__(self, name, lock_ttl=600): + if GlobalLock.lock_factory is None: + raise LockNotAcquiredException("GlobalLock not configured") + self._lock_name = name self._lock_ttl = lock_ttl self._redlock = None diff --git a/workers/blobuploadcleanupworker/blobuploadcleanupworker.py b/workers/blobuploadcleanupworker/blobuploadcleanupworker.py index 99db42f8e..ec9bc7569 100644 --- a/workers/blobuploadcleanupworker/blobuploadcleanupworker.py +++ b/workers/blobuploadcleanupworker/blobuploadcleanupworker.py @@ -86,5 +86,6 @@ def create_gunicorn_worker(): if __name__ == "__main__": logging.config.fileConfig(logfile_path(debug=False), disable_existing_loggers=False) + GlobalLock.configure(app.config) worker = BlobUploadCleanupWorker() worker.start() diff --git a/workers/gc/gcworker.py b/workers/gc/gcworker.py index a5b6ca752..4ec0e053b 100644 --- a/workers/gc/gcworker.py +++ b/workers/gc/gcworker.py @@ -91,5 +91,6 @@ if __name__ == "__main__": while True: time.sleep(100000) + GlobalLock.configure(app.config) worker = GarbageCollectionWorker() worker.start() diff --git a/workers/globalpromstats/globalpromstats.py b/workers/globalpromstats/globalpromstats.py index d3ff45287..6d6c233b1 100644 --- a/workers/globalpromstats/globalpromstats.py +++ b/workers/globalpromstats/globalpromstats.py @@ -87,6 +87,7 @@ def main(): while True: time.sleep(100000) + GlobalLock.configure(app.config) worker = GlobalPrometheusStatsWorker() worker.start() diff --git a/workers/logrotateworker.py b/workers/logrotateworker.py index d716c3136..84571efb3 100644 --- a/workers/logrotateworker.py +++ b/workers/logrotateworker.py @@ -153,6 +153,7 @@ def main(): while True: time.sleep(100000) + GlobalLock.configure(app.config) worker = LogRotateWorker() worker.start() diff --git a/workers/namespacegcworker.py b/workers/namespacegcworker.py index cf794727b..0ddc5da4c 100644 --- a/workers/namespacegcworker.py +++ b/workers/namespacegcworker.py @@ -69,6 +69,7 @@ if __name__ == "__main__": while True: time.sleep(100000) + GlobalLock.configure(app.config) logger.debug("Starting namespace GC worker") worker = NamespaceGCWorker( namespace_gc_queue, diff --git a/workers/repositorygcworker.py b/workers/repositorygcworker.py index cb428fb13..2088772c6 100644 --- a/workers/repositorygcworker.py +++ b/workers/repositorygcworker.py @@ -78,6 +78,7 @@ if __name__ == "__main__": while True: time.sleep(100000) + GlobalLock.configure(app.config) logger.debug("Starting repository GC worker") worker = RepositoryGCWorker( repository_gc_queue,