Skip to content

Commit ee6f962

Browse files
vladvildanovpetyaslavova
authored andcommitted
fix: Fixed potential deadlock from unexpected __del__ call (#3654)
1 parent 10b90af commit ee6f962

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
@@ -369,6 +369,8 @@ def __init__(
369369
]:
370370
raise RedisError("Client caching is only supported with RESP version 3")
371371

372+
# TODO: To avoid breaking changes during the bug fix, we have to keep non-reentrant lock.
373+
# TODO: Remove this before next major version (7.0.0)
372374
self.single_connection_lock = threading.Lock()
373375
self.connection = None
374376
self._single_connection_client = single_connection_client
@@ -774,6 +776,9 @@ def __init__(
774776
self._event_dispatcher = EventDispatcher()
775777
else:
776778
self._event_dispatcher = event_dispatcher
779+
780+
# TODO: To avoid breaking changes during the bug fix, we have to keep non-reentrant lock.
781+
# TODO: Remove this before next major version (7.0.0)
777782
self._lock = threading.Lock()
778783
if self.encoder is None:
779784
self.encoder = self.connection_pool.get_encoder()

redis/cluster.py

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

712712
self.commands_parser = CommandsParser(self)
713-
self._lock = threading.Lock()
713+
self._lock = threading.RLock()
714714

715715
def __enter__(self):
716716
return self
@@ -1474,7 +1474,7 @@ def __init__(
14741474
self.connection_kwargs = kwargs
14751475
self.read_load_balancer = LoadBalancer()
14761476
if lock is None:
1477-
lock = threading.Lock()
1477+
lock = threading.RLock()
14781478
self._lock = lock
14791479
if event_dispatcher is None:
14801480
self._event_dispatcher = EventDispatcher()
@@ -2178,7 +2178,7 @@ def __init__(
21782178
kwargs.get("decode_responses", False),
21792179
)
21802180
if lock is None:
2181-
lock = threading.Lock()
2181+
lock = threading.RLock()
21822182
self._lock = lock
21832183
self.parent_execute_command = super().execute_command
21842184
self._execution_strategy: ExecutionStrategy = (

redis/connection.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -820,7 +820,7 @@ def __init__(
820820
self.credential_provider = conn.credential_provider
821821
self._pool_lock = pool_lock
822822
self._cache = cache
823-
self._cache_lock = threading.Lock()
823+
self._cache_lock = threading.RLock()
824824
self._current_command_cache_key = None
825825
self._current_options = None
826826
self.register_connect_callback(self._enable_tracking_callback)
@@ -1420,8 +1420,16 @@ def __init__(
14201420
# object of this pool. subsequent threads acquiring this lock
14211421
# will notice the first thread already did the work and simply
14221422
# release the lock.
1423-
self._fork_lock = threading.Lock()
1424-
self._lock = threading.Lock()
1423+
1424+
self._fork_lock = threading.RLock()
1425+
1426+
if self.cache is None:
1427+
self._lock = threading.RLock()
1428+
else:
1429+
# TODO: To avoid breaking changes during the bug fix, we have to keep non-reentrant lock.
1430+
# TODO: Remove this before next major version (7.0.0)
1431+
self._lock = threading.Lock()
1432+
14251433
self.reset()
14261434

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

0 commit comments

Comments
 (0)