1
1
import asyncio
2
+ import logging
2
3
import threading
3
4
import uuid
4
5
from types import SimpleNamespace
10
11
if TYPE_CHECKING :
11
12
from redis .asyncio import Redis , RedisCluster
12
13
14
+ logger = logging .getLogger (__name__ )
15
+
13
16
14
17
class Lock :
15
18
"""
@@ -85,6 +88,7 @@ def __init__(
85
88
blocking : bool = True ,
86
89
blocking_timeout : Optional [Number ] = None ,
87
90
thread_local : bool = True ,
91
+ raise_on_release_error : bool = True ,
88
92
):
89
93
"""
90
94
Create a new Lock instance named ``name`` using the Redis client
@@ -128,6 +132,11 @@ def __init__(
128
132
thread-1 would see the token value as "xyz" and would be
129
133
able to successfully release the thread-2's lock.
130
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.
139
+
131
140
In some use cases it's necessary to disable thread local storage. For
132
141
example, if you have code where one thread acquires a lock and passes
133
142
that lock instance to a worker thread to release later. If thread
@@ -144,6 +153,7 @@ def __init__(
144
153
self .blocking_timeout = blocking_timeout
145
154
self .thread_local = bool (thread_local )
146
155
self .local = threading .local () if self .thread_local else SimpleNamespace ()
156
+ self .raise_on_release_error = raise_on_release_error
147
157
self .local .token = None
148
158
self .register_scripts ()
149
159
@@ -163,7 +173,14 @@ async def __aenter__(self):
163
173
raise LockError ("Unable to acquire lock within the time specified" )
164
174
165
175
async def __aexit__ (self , exc_type , exc_value , traceback ):
166
- await self .release ()
176
+ try :
177
+ await self .release ()
178
+ except LockError :
179
+ if self .raise_on_release_error :
180
+ raise
181
+ logger .warning (
182
+ "Lock was unlocked or no longer owned when exiting context manager."
183
+ )
167
184
168
185
async def acquire (
169
186
self ,
0 commit comments