Skip to content

Commit 14a6fc3

Browse files
authored
fix: Fixed potential deadlock from unexpected __del__ call (#3654)
1 parent 3ebfd5b commit 14a6fc3

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

371+
# TODO: To avoid breaking changes during the bug fix, we have to keep non-reentrant lock.
372+
# TODO: Remove this before next major version (7.0.0)
371373
self.single_connection_lock = threading.Lock()
372374
self.connection = None
373375
self._single_connection_client = single_connection_client
@@ -773,6 +775,9 @@ def __init__(
773775
self._event_dispatcher = EventDispatcher()
774776
else:
775777
self._event_dispatcher = event_dispatcher
778+
779+
# TODO: To avoid breaking changes during the bug fix, we have to keep non-reentrant lock.
780+
# TODO: Remove this before next major version (7.0.0)
776781
self._lock = threading.Lock()
777782
if self.encoder is None:
778783
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
@@ -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)