Skip to content

Commit 6b0abfb

Browse files
committed
Changing the default retry configuration for Redis standalone clients.
1 parent 0c24240 commit 6b0abfb

File tree

2 files changed

+42
-20
lines changed

2 files changed

+42
-20
lines changed

redis/client.py

+41-19
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
_RedisCallbacksRESP3,
2323
bool_ok,
2424
)
25+
from redis.backoff import ExponentialWithJitterBackoff
2526
from redis.cache import CacheConfig, CacheInterface
2627
from redis.commands import (
2728
CoreCommands,
@@ -57,6 +58,7 @@
5758
from redis.utils import (
5859
HIREDIS_AVAILABLE,
5960
_set_info_logger,
61+
deprecated_args,
6062
get_lib_version,
6163
safe_str,
6264
str_if_bytes,
@@ -188,6 +190,11 @@ def from_pool(
188190
client.auto_close_connection_pool = True
189191
return client
190192

193+
@deprecated_args(
194+
args_to_warn=["retry_on_timeout"],
195+
reason="TimeoutError is included by default.",
196+
version="6.0.0",
197+
)
191198
def __init__(
192199
self,
193200
host: str = "localhost",
@@ -204,6 +211,9 @@ def __init__(
204211
encoding_errors: str = "strict",
205212
decode_responses: bool = False,
206213
retry_on_timeout: bool = False,
214+
retry: Retry = Retry(
215+
backoff=ExponentialWithJitterBackoff(base=1, cap=10), retries=3
216+
),
207217
retry_on_error: Optional[List[Type[Exception]]] = None,
208218
ssl: bool = False,
209219
ssl_keyfile: Optional[str] = None,
@@ -227,7 +237,6 @@ def __init__(
227237
lib_name: Optional[str] = "redis-py",
228238
lib_version: Optional[str] = get_lib_version(),
229239
username: Optional[str] = None,
230-
retry: Optional[Retry] = None,
231240
redis_connect_func: Optional[Callable[[], None]] = None,
232241
credential_provider: Optional[CredentialProvider] = None,
233242
protocol: Optional[int] = 2,
@@ -237,10 +246,23 @@ def __init__(
237246
) -> None:
238247
"""
239248
Initialize a new Redis client.
240-
To specify a retry policy for specific errors, first set
241-
`retry_on_error` to a list of the error/s to retry on, then set
242-
`retry` to a valid `Retry` object.
243-
To retry on TimeoutError, `retry_on_timeout` can also be set to `True`.
249+
250+
To specify a retry policy for specific errors, you have two options:
251+
252+
1. Set the `retry_on_error` to a list of the error/s to retry on, and
253+
you can also set `retry` to a valid `Retry` object(in case the default
254+
one is not appropriate) - with this approach the retries will be triggered
255+
on the default errors specified in the Retry object enriched with the
256+
errors specified in `retry_on_error`.
257+
258+
2. Define a `Retry` object with configured 'supported_errors' and set
259+
it to the `retry` parameter - with this approach you completely redefine
260+
the errors on which retries will happen.
261+
262+
`retry_on_timeout` is deprecated - please include the TimeoutError
263+
either in the Retry object or in the `retry_on_error` list.
264+
When 'connection_pool' is provided - the retry configuration of the
265+
provided pool will be used.
244266
245267
Args:
246268
@@ -255,8 +277,6 @@ def __init__(
255277
if not connection_pool:
256278
if not retry_on_error:
257279
retry_on_error = []
258-
if retry_on_timeout is True:
259-
retry_on_error.append(TimeoutError)
260280
kwargs = {
261281
"db": db,
262282
"username": username,
@@ -378,10 +398,10 @@ def get_connection_kwargs(self) -> Dict:
378398
"""Get the connection's key-word arguments"""
379399
return self.connection_pool.connection_kwargs
380400

381-
def get_retry(self) -> Optional["Retry"]:
401+
def get_retry(self) -> Optional[Retry]:
382402
return self.get_connection_kwargs().get("retry")
383403

384-
def set_retry(self, retry: "Retry") -> None:
404+
def set_retry(self, retry: Retry) -> None:
385405
self.get_connection_kwargs().update({"retry": retry})
386406
self.connection_pool.set_retry(retry)
387407

@@ -581,18 +601,20 @@ def _send_command_parse_response(self, conn, command_name, *args, **options):
581601
conn.send_command(*args, **options)
582602
return self.parse_response(conn, command_name, **options)
583603

584-
def _disconnect_raise(self, conn, error):
604+
def _conditional_disconnect(self, conn, error) -> None:
585605
"""
586-
Close the connection and raise an exception
587-
if retry_on_error is not set or the error
588-
is not one of the specified error types
606+
Close the connection if the error is not TimeoutError.
607+
The supported exceptions are already checked in the
608+
retry object so we don't need to do it here.
609+
After we disconnect the connection, it will try to reconnect and
610+
do a health check as part of the send_command logic(on connection level).
589611
"""
612+
if isinstance(error, TimeoutError):
613+
# If the error is a TimeoutError, we don't want to
614+
# disconnect the connection. We want to retry the command.
615+
return
616+
590617
conn.disconnect()
591-
if (
592-
conn.retry_on_error is None
593-
or isinstance(error, tuple(conn.retry_on_error)) is False
594-
):
595-
raise error
596618

597619
# COMMAND EXECUTION AND PROTOCOL PARSING
598620
def execute_command(self, *args, **options):
@@ -611,7 +633,7 @@ def _execute_command(self, *args, **options):
611633
lambda: self._send_command_parse_response(
612634
conn, command_name, *args, **options
613635
),
614-
lambda error: self._disconnect_raise(conn, error),
636+
lambda error: self._conditional_disconnect(conn, error),
615637
)
616638
finally:
617639
if self._single_connection_client:

redis/connection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,7 @@ def close(self) -> None:
16111611
"""Close the pool, disconnecting all connections"""
16121612
self.disconnect()
16131613

1614-
def set_retry(self, retry: "Retry") -> None:
1614+
def set_retry(self, retry: Retry) -> None:
16151615
self.connection_kwargs.update({"retry": retry})
16161616
for conn in self._available_connections:
16171617
conn.retry = retry

0 commit comments

Comments
 (0)