Skip to content

Commit 137c931

Browse files
committed
Sync with master
1 parent a851942 commit 137c931

File tree

3 files changed

+50
-44
lines changed

3 files changed

+50
-44
lines changed

redis/cluster.py

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import time
66
from abc import ABC, abstractmethod
77
from collections import OrderedDict
8+
from copy import copy
89
from enum import Enum
910
from itertools import chain
1011
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
@@ -2166,7 +2167,7 @@ def __init__(
21662167
else:
21672168
self.retry = Retry(
21682169
backoff=ExponentialWithJitterBackoff(base=1, cap=10),
2169-
retries=self.cluster_error_retry_attempts,
2170+
retries=cluster_error_retry_attempts,
21702171
)
21712172

21722173
self.encoder = Encoder(
@@ -2178,10 +2179,8 @@ def __init__(
21782179
lock = threading.Lock()
21792180
self._lock = lock
21802181
self.parent_execute_command = super().execute_command
2181-
self._execution_strategy: ExecutionStrategy = PipelineStrategy(
2182-
self
2183-
) if not transaction else TransactionStrategy(
2184-
self
2182+
self._execution_strategy: ExecutionStrategy = (
2183+
PipelineStrategy(self) if not transaction else TransactionStrategy(self)
21852184
)
21862185
self.command_stack = self._execution_strategy.command_queue
21872186

@@ -2477,7 +2476,6 @@ def read(self):
24772476

24782477

24792478
class ExecutionStrategy(ABC):
2480-
24812479
@property
24822480
@abstractmethod
24832481
def command_queue(self):
@@ -2520,7 +2518,9 @@ def execute(self, raise_on_error: bool = True) -> List[Any]:
25202518
pass
25212519

25222520
@abstractmethod
2523-
def send_cluster_commands(self, stack, raise_on_error=True, allow_redirections=True):
2521+
def send_cluster_commands(
2522+
self, stack, raise_on_error=True, allow_redirections=True
2523+
):
25242524
"""
25252525
Sends commands according to current execution strategy.
25262526
@@ -2599,10 +2599,9 @@ def discard(self):
25992599

26002600

26012601
class AbstractStrategy(ExecutionStrategy):
2602-
26032602
def __init__(
2604-
self,
2605-
pipe: ClusterPipeline,
2603+
self,
2604+
pipe: ClusterPipeline,
26062605
):
26072606
self._command_queue: List[PipelineCommand] = []
26082607
self._pipe = pipe
@@ -2631,7 +2630,9 @@ def execute(self, raise_on_error: bool = True) -> List[Any]:
26312630
pass
26322631

26332632
@abstractmethod
2634-
def send_cluster_commands(self, stack, raise_on_error=True, allow_redirections=True):
2633+
def send_cluster_commands(
2634+
self, stack, raise_on_error=True, allow_redirections=True
2635+
):
26352636
pass
26362637

26372638
@abstractmethod
@@ -2666,8 +2667,8 @@ def annotate_exception(self, exception, number, command):
26662667
)
26672668
exception.args = (msg,) + exception.args[1:]
26682669

2669-
class PipelineStrategy(AbstractStrategy):
26702670

2671+
class PipelineStrategy(AbstractStrategy):
26712672
def __init__(self, pipe: ClusterPipeline):
26722673
super().__init__(pipe)
26732674
self.command_flags = pipe.command_flags
@@ -2702,10 +2703,7 @@ def reset(self):
27022703
self._command_queue = []
27032704

27042705
def send_cluster_commands(
2705-
self,
2706-
stack,
2707-
raise_on_error=True,
2708-
allow_redirections=True
2706+
self, stack, raise_on_error=True, allow_redirections=True
27092707
):
27102708
"""
27112709
Wrapper for CLUSTERDOWN error handling.
@@ -2724,7 +2722,7 @@ def send_cluster_commands(
27242722
"""
27252723
if not stack:
27262724
return []
2727-
retry_attempts = self._pipe.cluster_error_retry_attempts
2725+
retry_attempts = self._pipe.retry.get_retries()
27282726
while True:
27292727
try:
27302728
return self._send_cluster_commands(
@@ -2742,10 +2740,7 @@ def send_cluster_commands(
27422740
raise e
27432741

27442742
def _send_cluster_commands(
2745-
self,
2746-
stack,
2747-
raise_on_error=True,
2748-
allow_redirections=True
2743+
self, stack, raise_on_error=True, allow_redirections=True
27492744
):
27502745
"""
27512746
Send a bunch of cluster commands to the redis cluster.
@@ -2945,7 +2940,10 @@ def _determine_nodes(self, *args, **kwargs) -> List["ClusterNode"]:
29452940
# Determine which nodes should be executed the command on.
29462941
# Returns a list of target nodes.
29472942
command = args[0].upper()
2948-
if len(args) >= 2 and f"{args[0]} {args[1]}".upper() in self._pipe.command_flags:
2943+
if (
2944+
len(args) >= 2
2945+
and f"{args[0]} {args[1]}".upper() in self._pipe.command_flags
2946+
):
29492947
command = f"{args[0]} {args[1]}".upper()
29502948

29512949
nodes_flag = kwargs.pop("nodes_flag", None)
@@ -2978,7 +2976,9 @@ def _determine_nodes(self, *args, **kwargs) -> List["ClusterNode"]:
29782976
node = self._nodes_manager.get_node_from_slot(
29792977
slot,
29802978
self._pipe.read_from_replicas and command in READ_COMMANDS,
2981-
self._pipe.load_balancing_strategy if command in READ_COMMANDS else None,
2979+
self._pipe.load_balancing_strategy
2980+
if command in READ_COMMANDS
2981+
else None,
29822982
)
29832983
return [node]
29842984

@@ -3012,7 +3012,6 @@ def unlink(self, *names):
30123012

30133013

30143014
class TransactionStrategy(AbstractStrategy):
3015-
30163015
NO_SLOTS_COMMANDS = {"UNWATCH"}
30173016
IMMEDIATE_EXECUTE_COMMANDS = {"WATCH", "UNWATCH"}
30183017
UNWATCH_COMMANDS = {"DISCARD", "EXEC", "UNWATCH"}
@@ -3066,7 +3065,7 @@ def execute_command(self, *args, **kwargs):
30663065
slot_number = self._pipe.determine_slot(*args)
30673066

30683067
if (
3069-
self._watching or args[0] in self.IMMEDIATE_EXECUTE_COMMANDS
3068+
self._watching or args[0] in self.IMMEDIATE_EXECUTE_COMMANDS
30703069
) and not self._explicit_transaction:
30713070
if args[0] == "WATCH":
30723071
self._validate_watch()
@@ -3098,10 +3097,7 @@ def _validate_watch(self):
30983097
self._watching = True
30993098

31003099
def _immediate_execute_command(self, *args, **options):
3101-
retry = Retry(
3102-
default_backoff(),
3103-
self._pipe.cluster_error_retry_attempts,
3104-
)
3100+
retry = copy(self._pipe.retry)
31053101
retry.update_supported_errors([AskError, MovedError])
31063102
return retry.call_with_retry(
31073103
lambda: self._get_connection_and_send_command(*args, **options),
@@ -3175,10 +3171,7 @@ def execute(self, raise_on_error: bool = True) -> List[Any]:
31753171
def _execute_transaction_with_retries(
31763172
self, stack: List["PipelineCommand"], raise_on_error: bool
31773173
):
3178-
retry = Retry(
3179-
default_backoff(),
3180-
self._pipe.cluster_error_retry_attempts,
3181-
)
3174+
retry = copy(self._pipe.retry)
31823175
retry.update_supported_errors([AskError, MovedError])
31833176
return retry.call_with_retry(
31843177
lambda: self._execute_transaction(stack, raise_on_error),
@@ -3284,7 +3277,9 @@ def _execute_transaction(
32843277
if not isinstance(r, Exception):
32853278
command_name = cmd.args[0]
32863279
if command_name in self._pipe.cluster_response_callbacks:
3287-
r = self._pipe.cluster_response_callbacks[command_name](r, **cmd.options)
3280+
r = self._pipe.cluster_response_callbacks[command_name](
3281+
r, **cmd.options
3282+
)
32883283
data.append(r)
32893284
return data
32903285

@@ -3321,8 +3316,12 @@ def reset(self):
33213316
self._cluster_error = False
33223317
self._executing = False
33233318

3324-
def send_cluster_commands(self, stack, raise_on_error=True, allow_redirections=True):
3325-
raise NotImplementedError("send_cluster_commands cannot be executed in transactional context.")
3319+
def send_cluster_commands(
3320+
self, stack, raise_on_error=True, allow_redirections=True
3321+
):
3322+
raise NotImplementedError(
3323+
"send_cluster_commands cannot be executed in transactional context."
3324+
)
33263325

33273326
def multi(self):
33283327
if self._explicit_transaction:
@@ -3356,4 +3355,4 @@ def delete(self, *names):
33563355
return self.execute_command("DEL", *names)
33573356

33583357
def unlink(self, *names):
3359-
return self.execute_command("UNLINK", *names)
3358+
return self.execute_command("UNLINK", *names)

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from tests.ssl_utils import get_tls_certificates
3131

3232
REDIS_INFO = {}
33-
default_redis_url = "redis://localhost:6379/0"
33+
default_redis_url = "redis://localhost:16379/0"
3434
default_protocol = "2"
3535
default_redismod_url = "redis://localhost:6479"
3636

tests/test_cluster_transaction.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ def _find_source_and_target_node_for_slot(
3636

3737

3838
class TestClusterTransaction:
39-
4039
@pytest.mark.onlycluster
4140
def test_executes_transaction_against_cluster(self, r):
4241
with r.pipeline(transaction=True) as tx:
@@ -46,7 +45,14 @@ def test_executes_transaction_against_cluster(self, r):
4645
tx.get("{foo}bar")
4746
tx.get("{foo}baz")
4847
tx.get("{foo}bad")
49-
assert tx.execute() == [b"OK", b"OK", b"OK", b"value1", b"value2", b"value3"]
48+
assert tx.execute() == [
49+
b"OK",
50+
b"OK",
51+
b"OK",
52+
b"value1",
53+
b"value2",
54+
b"value3",
55+
]
5056

5157
r.flushall()
5258

@@ -66,8 +72,8 @@ def test_throws_exception_on_different_hash_slots(self, r):
6672
tx.set("{foobar}baz", "value2")
6773

6874
with pytest.raises(
69-
CrossSlotTransactionError,
70-
match="All keys involved in a cluster transaction must map to the same slot"
75+
CrossSlotTransactionError,
76+
match="All keys involved in a cluster transaction must map to the same slot",
7177
):
7278
tx.execute()
7379

@@ -201,7 +207,9 @@ def test_retry_transaction_on_connection_error(self, r, mock_connection):
201207
key = "book"
202208
slot = r.keyslot(key)
203209

204-
mock_connection.read_response.side_effect = redis.exceptions.ConnectionError("Conn error")
210+
mock_connection.read_response.side_effect = redis.exceptions.ConnectionError(
211+
"Conn error"
212+
)
205213
mock_connection.retry = Retry(NoBackoff(), 0)
206214
mock_pool = Mock(spec=ConnectionPool)
207215
mock_pool.get_connection.return_value = mock_connection
@@ -217,7 +225,6 @@ def test_retry_transaction_on_connection_error(self, r, mock_connection):
217225
pipe.set(key, "val")
218226
pipe.execute()
219227

220-
221228
# @pytest.mark.onlycluster
222229
# def test_pipeline_is_true(self, r):
223230
# "Ensure pipeline instances are not false-y"

0 commit comments

Comments
 (0)