@@ -13,37 +13,38 @@ class RetryHandler(BaseMiddleware):
1313 retry policy for all requests
1414 """
1515
16- DEFAULT_TOTAL_RETRIES = 3
17- MAX_TOTAL_RETRIES = 10
16+ DEFAULT_MAX_RETRIES = 3
17+ MAX_RETRIES = 10
18+ DEFAULT_DELAY = 3
19+ MAX_DELAY = 180
1820 DEFAULT_BACKOFF_FACTOR = 0.5
19- DEFAULT_RETRY_TIME_LIMIT = 180
2021 MAXIMUM_BACKOFF = 120
21- _DEFAULT_RETRY_CODES = {429 , 503 , 504 }
22+ _DEFAULT_RETRY_STATUS_CODES = {429 , 503 , 504 }
2223
2324 def __init__ (self , ** kwargs ):
2425 super ().__init__ ()
25- self .total_retries : int = min (
26- kwargs .pop ('retry_total ' , self .DEFAULT_TOTAL_RETRIES ), self .MAX_TOTAL_RETRIES
26+ self .max_retries : int = min (
27+ kwargs .pop ('max_retries ' , self .DEFAULT_MAX_RETRIES ), self .MAX_RETRIES
2728 )
2829 self .backoff_factor : float = kwargs .pop ('retry_backoff_factor' , self .DEFAULT_BACKOFF_FACTOR )
2930 self .backoff_max : int = kwargs .pop ('retry_backoff_max' , self .MAXIMUM_BACKOFF )
30- self .timeout : int = kwargs .pop ('retry_time_limit' , self .DEFAULT_RETRY_TIME_LIMIT )
31+ self .timeout : int = kwargs .pop ('retry_time_limit' , self .MAX_DELAY )
3132
3233 status_codes : [int ] = kwargs .pop ('retry_on_status_codes' , [])
3334
34- self ._retry_on_status_codes = set (status_codes ) | self ._DEFAULT_RETRY_CODES
35- self ._allowed_methods = frozenset (
35+ self ._retry_on_status_codes : set = set (status_codes ) | self ._DEFAULT_RETRY_STATUS_CODES
36+ self ._allowed_methods : set = frozenset (
3637 ['HEAD' , 'GET' , 'POST' , 'PUT' , 'PATCH' , 'DELETE' , 'OPTIONS' ]
3738 )
38- self ._respect_retry_after_header = True
39+ self ._respect_retry_after_header : bool = True
3940
4041 @classmethod
4142 def disable_retries (cls ):
4243 """
4344 Disable retries by setting retry_total to zero.
4445 retry_total takes precedence over all other counts.
4546 """
46- return cls (retry_total = 0 )
47+ return cls (max_retries = 0 )
4748
4849 def get_retry_options (self , middleware_control ):
4950 """
@@ -53,10 +54,7 @@ def get_retry_options(self, middleware_control):
5354 if middleware_control :
5455 return {
5556 'total' :
56- min (
57- middleware_control .get ('retry_total' , self .total_retries ),
58- self .MAX_TOTAL_RETRIES
59- ),
57+ min (middleware_control .get ('max_retries' , self .max_retries ), self .MAX_RETRIES ),
6058 'backoff' :
6159 middleware_control .get ('retry_backoff_factor' , self .backoff_factor ),
6260 'max_backoff' :
@@ -65,12 +63,12 @@ def get_retry_options(self, middleware_control):
6563 middleware_control .get ('retry_time_limit' , self .timeout ),
6664 'retry_codes' :
6765 set (middleware_control .get ('retry_on_status_codes' , self ._retry_on_status_codes ))
68- | set (self ._DEFAULT_RETRY_CODES ),
66+ | set (self ._DEFAULT_RETRY_STATUS_CODES ),
6967 'methods' :
7068 self ._allowed_methods ,
7169 }
7270 return {
73- 'total' : self .total_retries ,
71+ 'total' : self .max_retries ,
7472 'backoff' : self .backoff_factor ,
7573 'max_backoff' : self .backoff_max ,
7674 'timeout' : self .timeout ,
@@ -83,26 +81,32 @@ def send(self, request, **kwargs):
8381 Sends the http request object to the next middleware or retries the request if necessary.
8482 """
8583 retry_options = self .get_retry_options (request .context .middleware_control )
86- retry_active = True
87- absolute_time_limit = retry_options ['timeout' ]
84+ absolute_time_limit = min (retry_options ['timeout' ], self .MAX_DELAY )
8885 response = None
8986 retry_count = 0
87+ retry_valid = True
9088
91- while retry_active :
89+ while retry_valid :
9290 try :
9391 start_time = time .time ()
94- request .headers .update ({'Retry-Attempt ' : '{}' .format (retry_count )})
92+ request .headers .update ({'retry-attempt ' : '{}' .format (retry_count )})
9593 response = super ().send (request , ** kwargs )
96- # Check if the request needs to be retried based on the response
94+ # Check if the request needs to be retried based on the response method
95+ # and status code
9796 if self .should_retry (retry_options , response ):
98- retry_active = self .increment_counter (retry_options )
97+ # check that max retries has not been hit
98+ retry_valid = self .check_retry_valid (retry_options , retry_count )
99+
99100 # Get the delay time between retries
100- sleep_time = self .get_sleep_time (retry_options , retry_count , response )
101- if retry_active and sleep_time < absolute_time_limit :
102- time .sleep (sleep_time )
101+ delay = self .get_delay_time (retry_options , retry_count , response )
102+
103+ if retry_valid and delay < absolute_time_limit :
104+ time .sleep (delay )
103105 end_time = time .time ()
104106 absolute_time_limit -= (end_time - start_time )
107+ # increment the count for retries
105108 retry_count += 1
109+
106110 continue
107111 break
108112 except Exception as error :
@@ -142,35 +146,29 @@ def _is_request_payload_buffered(self, response):
142146 return False
143147 return True
144148
145- def increment_counter (self , retry_options ):
149+ def check_retry_valid (self , retry_options , retry_count ):
146150 """
147- Increment the retry counters on every valid retry
151+ Check that the max retries limit has not been hit
148152 """
149- if self .retries_exhausted (retry_options ):
150- return False
151- retry_options ['total' ] -= 1
152- return True
153-
154- def retries_exhausted (self , retry_options ):
155- retries_remaining = retry_options ['total' ]
156- if retries_remaining <= 0 :
153+ if retry_count < retry_options ['total' ]:
157154 return True
158155 return False
159156
160- def get_sleep_time (self , retry_options , retry_count , response = None ):
157+ def get_delay_time (self , retry_options , retry_count , response = None ):
161158 """
162- Get the time in seconds to sleep between retry attempts.
159+ Get the time in seconds to delay between retry attempts.
163160 Respects a retry-after header in the response if provided
164161 If no retry-after response header, it defaults to exponential backoff
165162 """
166163 retry_after = self ._get_retry_after (response )
167164 if retry_after :
168165 return retry_after
169- return self ._get_sleep_time_exp_backoff (retry_options , retry_count )
166+ return self ._get_delay_time_exp_backoff (retry_options , retry_count )
170167
171- def _get_sleep_time_exp_backoff (self , retry_options , retry_count ):
168+ def _get_delay_time_exp_backoff (self , retry_options , retry_count ):
172169 """
173- Get time to sleep based on exponential backoff value.
170+ Get time in seconds to delay between retry attempts based on an exponential
171+ backoff value.
174172 """
175173 exp_backoff_value = retry_options ['backoff' ] * + (2 ** (retry_count - 1 ))
176174 backoff_value = exp_backoff_value + (random .randint (0 , 1000 ) / 1000 )
@@ -182,7 +180,7 @@ def _get_retry_after(self, response):
182180 """
183181 Check if retry-after is specified in the response header and get the value
184182 """
185- retry_after = response .headers .get ("Retry-After " )
183+ retry_after = response .headers .get ("retry-after " )
186184 if retry_after :
187185 return self ._parse_retry_after (retry_after )
188186 return None
0 commit comments