22
22
_RedisCallbacksRESP3 ,
23
23
bool_ok ,
24
24
)
25
+ from redis .backoff import ExponentialWithJitterBackoff
25
26
from redis .cache import CacheConfig , CacheInterface
26
27
from redis .commands import (
27
28
CoreCommands ,
57
58
from redis .utils import (
58
59
HIREDIS_AVAILABLE ,
59
60
_set_info_logger ,
61
+ deprecated_args ,
60
62
get_lib_version ,
61
63
safe_str ,
62
64
str_if_bytes ,
@@ -188,6 +190,11 @@ def from_pool(
188
190
client .auto_close_connection_pool = True
189
191
return client
190
192
193
+ @deprecated_args (
194
+ args_to_warn = ["retry_on_timeout" ],
195
+ reason = "TimeoutError is included by default." ,
196
+ version = "6.0.0" ,
197
+ )
191
198
def __init__ (
192
199
self ,
193
200
host : str = "localhost" ,
@@ -204,6 +211,9 @@ def __init__(
204
211
encoding_errors : str = "strict" ,
205
212
decode_responses : bool = False ,
206
213
retry_on_timeout : bool = False ,
214
+ retry : Retry = Retry (
215
+ backoff = ExponentialWithJitterBackoff (base = 1 , cap = 10 ), retries = 3
216
+ ),
207
217
retry_on_error : Optional [List [Type [Exception ]]] = None ,
208
218
ssl : bool = False ,
209
219
ssl_keyfile : Optional [str ] = None ,
@@ -227,7 +237,6 @@ def __init__(
227
237
lib_name : Optional [str ] = "redis-py" ,
228
238
lib_version : Optional [str ] = get_lib_version (),
229
239
username : Optional [str ] = None ,
230
- retry : Optional [Retry ] = None ,
231
240
redis_connect_func : Optional [Callable [[], None ]] = None ,
232
241
credential_provider : Optional [CredentialProvider ] = None ,
233
242
protocol : Optional [int ] = 2 ,
@@ -237,10 +246,23 @@ def __init__(
237
246
) -> None :
238
247
"""
239
248
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.
244
266
245
267
Args:
246
268
@@ -255,8 +277,6 @@ def __init__(
255
277
if not connection_pool :
256
278
if not retry_on_error :
257
279
retry_on_error = []
258
- if retry_on_timeout is True :
259
- retry_on_error .append (TimeoutError )
260
280
kwargs = {
261
281
"db" : db ,
262
282
"username" : username ,
@@ -378,10 +398,10 @@ def get_connection_kwargs(self) -> Dict:
378
398
"""Get the connection's key-word arguments"""
379
399
return self .connection_pool .connection_kwargs
380
400
381
- def get_retry (self ) -> Optional [" Retry" ]:
401
+ def get_retry (self ) -> Optional [Retry ]:
382
402
return self .get_connection_kwargs ().get ("retry" )
383
403
384
- def set_retry (self , retry : " Retry" ) -> None :
404
+ def set_retry (self , retry : Retry ) -> None :
385
405
self .get_connection_kwargs ().update ({"retry" : retry })
386
406
self .connection_pool .set_retry (retry )
387
407
@@ -581,18 +601,20 @@ def _send_command_parse_response(self, conn, command_name, *args, **options):
581
601
conn .send_command (* args , ** options )
582
602
return self .parse_response (conn , command_name , ** options )
583
603
584
- def _disconnect_raise (self , conn , error ):
604
+ def _conditional_disconnect (self , conn , error ) -> None :
585
605
"""
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).
589
611
"""
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
+
590
617
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
596
618
597
619
# COMMAND EXECUTION AND PROTOCOL PARSING
598
620
def execute_command (self , * args , ** options ):
@@ -611,7 +633,7 @@ def _execute_command(self, *args, **options):
611
633
lambda : self ._send_command_parse_response (
612
634
conn , command_name , * args , ** options
613
635
),
614
- lambda error : self ._disconnect_raise (conn , error ),
636
+ lambda error : self ._conditional_disconnect (conn , error ),
615
637
)
616
638
finally :
617
639
if self ._single_connection_client :
0 commit comments