Skip to content

Commit d464d68

Browse files
committed
[GROW-3134] release already acquired connections, when get_connections raised an exception
1 parent 8a7897c commit d464d68

File tree

2 files changed

+29
-0
lines changed

2 files changed

+29
-0
lines changed

redis/cluster.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,6 +2026,8 @@ def _send_cluster_commands(
20262026
try:
20272027
connection = get_connection(redis_node, c.args)
20282028
except (ConnectionError, TimeoutError) as e:
2029+
for n in nodes.values():
2030+
n.connection_pool.release(n.connection)
20292031
if self.retry and isinstance(e, self.retry._supported_errors):
20302032
backoff = self.retry._backoff.compute(attempts_count)
20312033
if backoff > 0:

tests/test_cluster.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import pytest
1414

15+
import redis.cluster
1516
from redis import Redis
1617
from redis.backoff import (
1718
ConstantBackoff,
@@ -3048,6 +3049,32 @@ def raise_ask_error():
30483049
assert ask_node.redis_connection.connection.read_response.called
30493050
assert res == ["MOCK_OK"]
30503051

3052+
@pytest.mark.parametrize("error", [ConnectionError, TimeoutError])
3053+
def test_return_previous_acquired_connections(self, r, error):
3054+
# in order to ensure that a pipeline will make use of connections
3055+
# from different nodes
3056+
assert r.keyslot('a') != r.keyslot('b')
3057+
3058+
orig_func = redis.cluster.get_connection
3059+
with patch("redis.cluster.get_connection") as get_connection:
3060+
def raise_error(target_node, *args, **kwargs):
3061+
if get_connection.call_count == 2:
3062+
raise error("mocked error")
3063+
else:
3064+
return orig_func(target_node, *args, **kwargs)
3065+
3066+
get_connection.side_effect = raise_error
3067+
3068+
r.pipeline().get('a').get('b').execute()
3069+
3070+
# there should have been two get_connections per execution and
3071+
# two executions due to exception raised in the first execution
3072+
assert get_connection.call_count == 4
3073+
for cluster_node in r.nodes_manager.nodes_cache.values():
3074+
connection_pool = cluster_node.redis_connection.connection_pool
3075+
num_of_conns = len(connection_pool._available_connections)
3076+
assert num_of_conns == connection_pool._created_connections
3077+
30513078
def test_empty_stack(self, r):
30523079
"""
30533080
If pipeline is executed with no commands it should

0 commit comments

Comments
 (0)