Skip to content

Commit 0b743ab

Browse files
vladvildanovManelCoutinhoSensei
authored andcommitted
fix: Fixed potential deadlock from unexpected __del__ call (redis#3654)
1 parent 2e5b9ed commit 0b743ab

File tree

3 files changed

+19
-6
lines changed

3 files changed

+19
-6
lines changed

redis/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ def __init__(
371371
]:
372372
raise RedisError("Client caching is only supported with RESP version 3")
373373

374+
# TODO: To avoid breaking changes during the bug fix, we have to keep non-reentrant lock.
375+
# TODO: Remove this before next major version (7.0.0)
374376
self.single_connection_lock = threading.Lock()
375377
self.connection = None
376378
self._single_connection_client = single_connection_client
@@ -776,6 +778,9 @@ def __init__(
776778
self._event_dispatcher = EventDispatcher()
777779
else:
778780
self._event_dispatcher = event_dispatcher
781+
782+
# TODO: To avoid breaking changes during the bug fix, we have to keep non-reentrant lock.
783+
# TODO: Remove this before next major version (7.0.0)
779784
self._lock = threading.Lock()
780785
if self.encoder is None:
781786
self.encoder = self.connection_pool.get_encoder()

redis/cluster.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ def __init__(
709709
self.result_callbacks = CaseInsensitiveDict(self.__class__.RESULT_CALLBACKS)
710710

711711
self.commands_parser = CommandsParser(self)
712-
self._lock = threading.Lock()
712+
self._lock = threading.RLock()
713713

714714
def __enter__(self):
715715
return self
@@ -1473,7 +1473,7 @@ def __init__(
14731473
self.connection_kwargs = kwargs
14741474
self.read_load_balancer = LoadBalancer()
14751475
if lock is None:
1476-
lock = threading.Lock()
1476+
lock = threading.RLock()
14771477
self._lock = lock
14781478
if event_dispatcher is None:
14791479
self._event_dispatcher = EventDispatcher()
@@ -2177,7 +2177,7 @@ def __init__(
21772177
kwargs.get("decode_responses", False),
21782178
)
21792179
if lock is None:
2180-
lock = threading.Lock()
2180+
lock = threading.RLock()
21812181
self._lock = lock
21822182
self.parent_execute_command = super().execute_command
21832183
self._execution_strategy: ExecutionStrategy = (

redis/connection.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ def __init__(
842842
self.credential_provider = conn.credential_provider
843843
self._pool_lock = pool_lock
844844
self._cache = cache
845-
self._cache_lock = threading.Lock()
845+
self._cache_lock = threading.RLock()
846846
self._current_command_cache_key = None
847847
self._current_options = None
848848
self.register_connect_callback(self._enable_tracking_callback)
@@ -1442,8 +1442,16 @@ def __init__(
14421442
# object of this pool. subsequent threads acquiring this lock
14431443
# will notice the first thread already did the work and simply
14441444
# release the lock.
1445-
self._fork_lock = threading.Lock()
1446-
self._lock = threading.Lock()
1445+
1446+
self._fork_lock = threading.RLock()
1447+
1448+
if self.cache is None:
1449+
self._lock = threading.RLock()
1450+
else:
1451+
# TODO: To avoid breaking changes during the bug fix, we have to keep non-reentrant lock.
1452+
# TODO: Remove this before next major version (7.0.0)
1453+
self._lock = threading.Lock()
1454+
14471455
self.reset()
14481456

14491457
def __repr__(self) -> (str, str):

0 commit comments

Comments
 (0)