23
23
_RedisCallbacksRESP3 ,
24
24
bool_ok ,
25
25
)
26
+ from redis .backoff import ExponentialWithJitterBackoff
26
27
from redis .cache import CacheConfig , CacheInterface
27
28
from redis .commands import (
28
29
CoreCommands ,
58
59
from redis .utils import (
59
60
HIREDIS_AVAILABLE ,
60
61
_set_info_logger ,
62
+ deprecated_args ,
61
63
get_lib_version ,
62
64
safe_str ,
63
65
str_if_bytes ,
@@ -189,6 +191,11 @@ def from_pool(
189
191
client .auto_close_connection_pool = True
190
192
return client
191
193
194
+ @deprecated_args (
195
+ args_to_warn = ["retry_on_timeout" ],
196
+ reason = "TimeoutError is included by default." ,
197
+ version = "6.1.0" ,
198
+ )
192
199
def __init__ (
193
200
self ,
194
201
host : str = "localhost" ,
@@ -203,8 +210,6 @@ def __init__(
203
210
unix_socket_path : Optional [str ] = None ,
204
211
encoding : str = "utf-8" ,
205
212
encoding_errors : str = "strict" ,
206
- charset : Optional [str ] = None ,
207
- errors : Optional [str ] = None ,
208
213
decode_responses : bool = False ,
209
214
retry_on_timeout : bool = False ,
210
215
retry_on_error : Optional [List [Type [Exception ]]] = None ,
@@ -230,7 +235,9 @@ def __init__(
230
235
lib_name : Optional [str ] = "redis-py" ,
231
236
lib_version : Optional [str ] = get_lib_version (),
232
237
username : Optional [str ] = None ,
233
- retry : Optional [Retry ] = None ,
238
+ retry : Optional [Retry ] = Retry (
239
+ backoff = ExponentialWithJitterBackoff (base = 0.1 , cap = 5 ), retries = 3
240
+ ),
234
241
redis_connect_func : Optional [Callable [[], None ]] = None ,
235
242
credential_provider : Optional [CredentialProvider ] = None ,
236
243
protocol : Optional [int ] = 2 ,
@@ -240,10 +247,24 @@ def __init__(
240
247
) -> None :
241
248
"""
242
249
Initialize a new Redis client.
243
- To specify a retry policy for specific errors, first set
244
- `retry_on_error` to a list of the error/s to retry on, then set
245
- `retry` to a valid `Retry` object.
246
- To retry on TimeoutError, `retry_on_timeout` can also be set to `True`.
250
+
251
+ To specify a retry policy for specific errors, you have two options:
252
+
253
+ 1. Set the `retry_on_error` to a list of the error/s to retry on, and
254
+ you can also set `retry` to a valid `Retry` object(in case the default
255
+ one is not appropriate) - with this approach the retries will be triggered
256
+ on the default errors specified in the Retry object enriched with the
257
+ errors specified in `retry_on_error`.
258
+
259
+ 2. Define a `Retry` object with configured 'supported_errors' and set
260
+ it to the `retry` parameter - with this approach you completely redefine
261
+ the errors on which retries will happen.
262
+
263
+ `retry_on_timeout` is deprecated - please include the TimeoutError
264
+ either in the Retry object or in the `retry_on_error` list.
265
+
266
+ When 'connection_pool' is provided - the retry configuration of the
267
+ provided pool will be used.
247
268
248
269
Args:
249
270
@@ -256,24 +277,8 @@ def __init__(
256
277
else :
257
278
self ._event_dispatcher = event_dispatcher
258
279
if not connection_pool :
259
- if charset is not None :
260
- warnings .warn (
261
- DeprecationWarning (
262
- '"charset" is deprecated. Use "encoding" instead'
263
- )
264
- )
265
- encoding = charset
266
- if errors is not None :
267
- warnings .warn (
268
- DeprecationWarning (
269
- '"errors" is deprecated. Use "encoding_errors" instead'
270
- )
271
- )
272
- encoding_errors = errors
273
280
if not retry_on_error :
274
281
retry_on_error = []
275
- if retry_on_timeout is True :
276
- retry_on_error .append (TimeoutError )
277
282
kwargs = {
278
283
"db" : db ,
279
284
"username" : username ,
@@ -395,10 +400,10 @@ def get_connection_kwargs(self) -> Dict:
395
400
"""Get the connection's key-word arguments"""
396
401
return self .connection_pool .connection_kwargs
397
402
398
- def get_retry (self ) -> Optional [ " Retry" ] :
403
+ def get_retry (self ) -> Retry :
399
404
return self .get_connection_kwargs ().get ("retry" )
400
405
401
- def set_retry (self , retry : " Retry" ) -> None :
406
+ def set_retry (self , retry : Retry ) -> None :
402
407
self .get_connection_kwargs ().update ({"retry" : retry })
403
408
self .connection_pool .set_retry (retry )
404
409
@@ -598,18 +603,20 @@ def _send_command_parse_response(self, conn, command_name, *args, **options):
598
603
conn .send_command (* args , ** options )
599
604
return self .parse_response (conn , command_name , ** options )
600
605
601
- def _disconnect_raise (self , conn , error ):
606
+ def _conditional_disconnect (self , conn , error ) -> None :
602
607
"""
603
- Close the connection and raise an exception
604
- if retry_on_error is not set or the error
605
- is not one of the specified error types
608
+ Close the connection if the error is not TimeoutError.
609
+ The supported exceptions are already checked in the
610
+ retry object so we don't need to do it here.
611
+ After we disconnect the connection, it will try to reconnect and
612
+ do a health check as part of the send_command logic(on connection level).
606
613
"""
614
+ if isinstance (error , TimeoutError ):
615
+ # If the error is a TimeoutError, we don't want to
616
+ # disconnect the connection. We want to retry the command.
617
+ return
618
+
607
619
conn .disconnect ()
608
- if (
609
- conn .retry_on_error is None
610
- or isinstance (error , tuple (conn .retry_on_error )) is False
611
- ):
612
- raise error
613
620
614
621
# COMMAND EXECUTION AND PROTOCOL PARSING
615
622
def execute_command (self , * args , ** options ):
@@ -619,17 +626,20 @@ def _execute_command(self, *args, **options):
619
626
"""Execute a command and return a parsed response"""
620
627
pool = self .connection_pool
621
628
command_name = args [0 ]
629
+
622
630
conn = self .connection or pool .get_connection ()
623
631
624
632
if self ._single_connection_client :
625
633
self .single_connection_lock .acquire ()
634
+
626
635
try :
627
636
return conn .retry .call_with_retry (
628
637
lambda : self ._send_command_parse_response (
629
638
conn , command_name , * args , ** options
630
639
),
631
- lambda error : self ._disconnect_raise (conn , error ),
640
+ lambda error : self ._conditional_disconnect (conn , error ),
632
641
)
642
+
633
643
finally :
634
644
if self ._single_connection_client :
635
645
self .single_connection_lock .release ()
0 commit comments