Skip to content

Commit 98d2346

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

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
@@ -2025,6 +2025,8 @@ def _send_cluster_commands(
20252025
try:
20262026
connection = get_connection(redis_node, c.args)
20272027
except (ConnectionError, TimeoutError) as e:
2028+
for n in nodes.values():
2029+
n.connection_pool.release(n.connection)
20282030
if self.retry and isinstance(e, self.retry._supported_errors):
20292031
backoff = self.retry._backoff.compute(attempts_count)
20302032
if backoff > 0:

tests/test_cluster.py

Lines changed: 28 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,33 @@ 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+
3061+
def raise_error(target_node, *args, **kwargs):
3062+
if get_connection.call_count == 2:
3063+
raise error("mocked error")
3064+
else:
3065+
return orig_func(target_node, *args, **kwargs)
3066+
3067+
get_connection.side_effect = raise_error
3068+
3069+
r.pipeline().get("a").get("b").execute()
3070+
3071+
# there should have been two get_connections per execution and
3072+
# two executions due to exception raised in the first execution
3073+
assert get_connection.call_count == 4
3074+
for cluster_node in r.nodes_manager.nodes_cache.values():
3075+
connection_pool = cluster_node.redis_connection.connection_pool
3076+
num_of_conns = len(connection_pool._available_connections)
3077+
assert num_of_conns == connection_pool._created_connections
3078+
30513079
def test_empty_stack(self, r):
30523080
"""
30533081
If pipeline is executed with no commands it should

0 commit comments

Comments
 (0)