Skip to content

Commit 36ef785

Browse files
committed
[GROW-3134] release already acquired connections, when get_connections raised an exception (redis#3)
* [GROW-3134] release already acquired connections, when get_connections raised an exception * fix style (cherry picked from commit 94bb915)
1 parent 28d80e1 commit 36ef785

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

redis/cluster.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,6 +1995,8 @@ def _send_cluster_commands(
19951995
try:
19961996
connection = get_connection(redis_node, c.args)
19971997
except (ConnectionError, TimeoutError) as e:
1998+
for n in nodes.values():
1999+
n.connection_pool.release(n.connection)
19982000
if self.retry and isinstance(e, self.retry._supported_errors):
19992001
backoff = self.retry._backoff.compute(attempts_count)
20002002
if backoff > 0:

tests/test_cluster.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import pytest
99

10+
import redis.cluster
1011
from redis import Redis
1112
from redis.backoff import (
1213
ConstantBackoff,
@@ -2893,6 +2894,33 @@ def raise_ask_error():
28932894
assert ask_node.redis_connection.connection.read_response.called
28942895
assert res == ["MOCK_OK"]
28952896

2897+
@pytest.mark.parametrize("error", [ConnectionError, TimeoutError])
2898+
def test_return_previous_acquired_connections(self, r, error):
2899+
# in order to ensure that a pipeline will make use of connections
2900+
# from different nodes
2901+
assert r.keyslot("a") != r.keyslot("b")
2902+
2903+
orig_func = redis.cluster.get_connection
2904+
with patch("redis.cluster.get_connection") as get_connection:
2905+
2906+
def raise_error(target_node, *args, **kwargs):
2907+
if get_connection.call_count == 2:
2908+
raise error("mocked error")
2909+
else:
2910+
return orig_func(target_node, *args, **kwargs)
2911+
2912+
get_connection.side_effect = raise_error
2913+
2914+
r.pipeline().get("a").get("b").execute()
2915+
2916+
# there should have been two get_connections per execution and
2917+
# two executions due to exception raised in the first execution
2918+
assert get_connection.call_count == 4
2919+
for cluster_node in r.nodes_manager.nodes_cache.values():
2920+
connection_pool = cluster_node.redis_connection.connection_pool
2921+
num_of_conns = len(connection_pool._available_connections)
2922+
assert num_of_conns == connection_pool._created_connections
2923+
28962924
def test_empty_stack(self, r):
28972925
"""
28982926
If pipeline is executed with no commands it should

0 commit comments

Comments
 (0)