aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/decorators.py6
-rw-r--r--bot/utils/__init__.py3
-rw-r--r--bot/utils/lock.py23
3 files changed, 28 insertions, 4 deletions
diff --git a/bot/decorators.py b/bot/decorators.py
index 0e84cf37e..3418dfd11 100644
--- a/bot/decorators.py
+++ b/bot/decorators.py
@@ -13,7 +13,7 @@ from discord.ext.commands import Cog, Context, check
from bot.constants import Channels, ERROR_REPLIES, RedirectOutput
from bot.errors import LockedResourceError
-from bot.utils import function
+from bot.utils import LockGuard, function
from bot.utils.checks import in_whitelist_check, with_role_check, without_role_check
log = logging.getLogger(__name__)
@@ -144,11 +144,11 @@ def mutually_exclusive(
# Get the lock for the ID. Create a lock if one doesn't exist yet.
locks = __lock_dicts[namespace]
- lock = locks.setdefault(id_, asyncio.Lock())
+ lock = locks.setdefault(id_, LockGuard())
if not lock.locked():
log.debug(f"{name}: resource {namespace!r}:{id_!r} is free; acquiring it...")
- async with lock:
+ with lock:
return await func(*args, **kwargs)
else:
log.info(f"{name}: aborted because resource {namespace!r}:{id_!r} is locked")
diff --git a/bot/utils/__init__.py b/bot/utils/__init__.py
index 5a6e1811b..0dd9605e8 100644
--- a/bot/utils/__init__.py
+++ b/bot/utils/__init__.py
@@ -2,9 +2,10 @@ from abc import ABCMeta
from discord.ext.commands import CogMeta
+from bot.utils.lock import LockGuard
from bot.utils.redis_cache import RedisCache
-__all__ = ['RedisCache', 'CogABCMeta']
+__all__ = ["CogABCMeta", "LockGuard", "RedisCache"]
class CogABCMeta(CogMeta, ABCMeta):
diff --git a/bot/utils/lock.py b/bot/utils/lock.py
new file mode 100644
index 000000000..8f1b738aa
--- /dev/null
+++ b/bot/utils/lock.py
@@ -0,0 +1,23 @@
+class LockGuard:
+ """
+ A context manager which acquires and releases a lock (mutex).
+
+ Raise RuntimeError if trying to acquire a locked lock.
+ """
+
+ def __init__(self):
+ self._locked = False
+
+ def locked(self) -> bool:
+ """Return True if currently locked or False if unlocked."""
+ return self._locked
+
+ def __enter__(self):
+ if self._locked:
+ raise RuntimeError("Cannot acquire a locked lock.")
+
+ self._locked = True
+
+ def __exit__(self, _exc_type, _exc_value, _traceback): # noqa: ANN001
+ self._locked = False
+ return False # Indicate any raised exception shouldn't be suppressed.