Skip to content

Commit 16daa68

Browse files
committed
added some warning for long exclusive and semaphore locks
1 parent 10fdc33 commit 16daa68

File tree

3 files changed

+33
-1
lines changed

3 files changed

+33
-1
lines changed

packages/service-library/src/servicelib/redis/_constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
from pydantic import NonNegativeInt
55

6+
DEFAULT_EXPECTED_LOCK_OVERALL_TIME: Final[datetime.timedelta] = datetime.timedelta(
7+
seconds=30
8+
)
69
DEFAULT_LOCK_TTL: Final[datetime.timedelta] = datetime.timedelta(seconds=10)
710
DEFAULT_SOCKET_TIMEOUT: Final[datetime.timedelta] = datetime.timedelta(seconds=30)
811

packages/service-library/src/servicelib/redis/_decorators.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from ..background_task import periodic
1616
from ._client import RedisClientSDK
17-
from ._constants import DEFAULT_LOCK_TTL
17+
from ._constants import DEFAULT_EXPECTED_LOCK_OVERALL_TIME, DEFAULT_LOCK_TTL
1818
from ._errors import CouldNotAcquireLockError, LockLostError
1919
from ._utils import auto_extend_lock
2020

@@ -95,6 +95,7 @@ async def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
9595
):
9696
raise CouldNotAcquireLockError(lock=lock)
9797

98+
lock_acquisition_time = arrow.utcnow()
9899
try:
99100
async with asyncio.TaskGroup() as tg:
100101
started_event = asyncio.Event()
@@ -157,6 +158,19 @@ async def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
157158
"Look for synchronous code that prevents refreshing the lock or asyncio loop overload.",
158159
)
159160
)
161+
finally:
162+
lock_release_time = arrow.utcnow()
163+
locking_time = lock_release_time - lock_acquisition_time
164+
if locking_time > DEFAULT_EXPECTED_LOCK_OVERALL_TIME:
165+
_logger.warning(
166+
"Lock `%s'for %s was held for %s which is longer than the expected (%s). "
167+
"TIP: consider reducing the locking time by optimizing the code inside "
168+
"the critical section or increasing the default locking time",
169+
redis_lock_key,
170+
coro.__name__,
171+
locking_time,
172+
DEFAULT_EXPECTED_LOCK_OVERALL_TIME,
173+
)
160174

161175
return _wrapper
162176

packages/service-library/src/servicelib/redis/_semaphore_decorator.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
from contextlib import AbstractAsyncContextManager, asynccontextmanager
88
from typing import Any, ParamSpec, TypeVar
99

10+
import arrow
1011
from common_library.async_tools import cancel_wait_task
1112
from common_library.logging.logging_errors import create_troubleshooting_log_kwargs
1213

1314
from ..background_task import periodic
1415
from ._client import RedisClientSDK
1516
from ._constants import (
17+
DEFAULT_EXPECTED_LOCK_OVERALL_TIME,
1618
DEFAULT_SEMAPHORE_TTL,
1719
DEFAULT_SOCKET_TIMEOUT,
1820
)
@@ -42,6 +44,7 @@ async def _managed_semaphore_execution(
4244
if not await semaphore.acquire():
4345
raise SemaphoreAcquisitionError(name=semaphore_key, capacity=semaphore.capacity)
4446

47+
lock_acquisition_time = arrow.utcnow()
4548
try:
4649
# NOTE: Use TaskGroup for proper exception propagation, this ensures that in case of error the context manager will be properly exited
4750
# and the semaphore released.
@@ -100,6 +103,18 @@ async def _periodic_renewer() -> None:
100103
"Look for synchronous code that prevents refreshing the semaphore or asyncio loop overload.",
101104
)
102105
)
106+
finally:
107+
lock_release_time = arrow.utcnow()
108+
locking_time = lock_release_time - lock_acquisition_time
109+
if locking_time > DEFAULT_EXPECTED_LOCK_OVERALL_TIME:
110+
_logger.warning(
111+
"Semaphore '%s' was held for %s which is longer than expected (%s). "
112+
"TIP: consider reducing the locking time by optimizing the code inside "
113+
"the critical section or increasing the default locking time",
114+
semaphore_key,
115+
locking_time,
116+
DEFAULT_EXPECTED_LOCK_OVERALL_TIME,
117+
)
103118

104119

105120
def _create_semaphore(

0 commit comments

Comments
 (0)