11import asyncio
22import threading
33import uuid
4+ import logging
45from types import SimpleNamespace
56from typing import TYPE_CHECKING , Awaitable , Optional , Union
67
1011if TYPE_CHECKING :
1112 from redis .asyncio import Redis , RedisCluster
1213
14+ logger = logging .getLogger (__name__ )
15+
1316
1417class Lock :
1518 """
@@ -85,6 +88,7 @@ def __init__(
8588 blocking : bool = True ,
8689 blocking_timeout : Optional [Number ] = None ,
8790 thread_local : bool = True ,
91+ raise_on_release_error : bool = True ,
8892 ):
8993 """
9094 Create a new Lock instance named ``name`` using the Redis client
@@ -127,6 +131,11 @@ def __init__(
127131 token is *not* stored in thread local storage, then
128132 thread-1 would see the token value as "xyz" and would be
129133 able to successfully release the thread-2's lock.
134+
135+ ``raise_on_release_error`` indicates whether to raise an exception when
136+ the lock is no longer owned when exiting the context manager. By default,
137+ this is True, meaning an exception will be raised. If False, the warning
138+ will be logged and the exception will be suppressed.
130139
131140 In some use cases it's necessary to disable thread local storage. For
132141 example, if you have code where one thread acquires a lock and passes
@@ -144,6 +153,7 @@ def __init__(
144153 self .blocking_timeout = blocking_timeout
145154 self .thread_local = bool (thread_local )
146155 self .local = threading .local () if self .thread_local else SimpleNamespace ()
156+ self .raise_on_release_error = raise_on_release_error
147157 self .local .token = None
148158 self .register_scripts ()
149159
@@ -163,7 +173,13 @@ async def __aenter__(self):
163173 raise LockError ("Unable to acquire lock within the time specified" )
164174
165175 async def __aexit__ (self , exc_type , exc_value , traceback ):
166- await self .release ()
176+ try :
177+ await self .release ()
178+ except LockNotOwnedError as e :
179+ if self .raise_on_release_error :
180+ raise e
181+ logger .warning ("Lock was no longer owned when exiting context manager." )
182+
167183
168184 async def acquire (
169185 self ,
0 commit comments