11import asyncio
22import threading
33import uuid
4+ import logging
45from types import SimpleNamespace
56from typing import TYPE_CHECKING , Awaitable , Optional , Union
67
910if TYPE_CHECKING :
1011 from redis .asyncio import Redis , RedisCluster
1112
13+ logger = logging .getLogger (__name__ )
14+
1215
1316class Lock :
1417 """
@@ -84,6 +87,7 @@ def __init__(
8487 blocking : bool = True ,
8588 blocking_timeout : Optional [float ] = None ,
8689 thread_local : bool = True ,
90+ raise_on_release_error : bool = True ,
8791 ):
8892 """
8993 Create a new Lock instance named ``name`` using the Redis client
@@ -126,6 +130,11 @@ def __init__(
126130 token is *not* stored in thread local storage, then
127131 thread-1 would see the token value as "xyz" and would be
128132 able to successfully release the thread-2's lock.
133+
134+ ``raise_on_release_error`` indicates whether to raise an exception when
135+ the lock is no longer owned when exiting the context manager. By default,
136+ this is True, meaning an exception will be raised. If False, the warning
137+ will be logged and the exception will be suppressed.
129138
130139 In some use cases it's necessary to disable thread local storage. For
131140 example, if you have code where one thread acquires a lock and passes
@@ -143,6 +152,7 @@ def __init__(
143152 self .blocking_timeout = blocking_timeout
144153 self .thread_local = bool (thread_local )
145154 self .local = threading .local () if self .thread_local else SimpleNamespace ()
155+ self .raise_on_release_error = raise_on_release_error
146156 self .local .token = None
147157 self .register_scripts ()
148158
@@ -162,7 +172,13 @@ async def __aenter__(self):
162172 raise LockError ("Unable to acquire lock within the time specified" )
163173
164174 async def __aexit__ (self , exc_type , exc_value , traceback ):
165- await self .release ()
175+ try :
176+ await self .release ()
177+ except LockNotOwnedError as e :
178+ if self .raise_on_release_error :
179+ raise e
180+ logger .warning ("Lock was no longer owned when exiting context manager." )
181+
166182
167183 async def acquire (
168184 self ,
0 commit comments