12
12
from boto .exception import BotoServerError
13
13
from botocore .exceptions import ClientError
14
14
from boto .pyami .config import Config
15
- import botocore
16
- from typing import Tuple , TYPE_CHECKING
15
+ from typing import Tuple , TYPE_CHECKING , Iterable , Any , Optional
17
16
18
17
if TYPE_CHECKING :
19
18
import mypy_boto3_rds
@@ -138,12 +137,17 @@ def get_access_key_id():
138
137
return os .environ .get ("EC2_ACCESS_KEY" ) or os .environ .get ("AWS_ACCESS_KEY_ID" )
139
138
140
139
141
- def retry (f , error_codes = [], logger = None ):
140
+ def retry (
141
+ f , error_codes : Optional [Iterable [Any ]] = None , logger = None , num_retries : int = 7
142
+ ):
142
143
"""
143
144
Retry function f up to 7 times. If error_codes argument is empty list, retry on all EC2 response errors,
144
145
otherwise, only on the specified error codes.
145
146
"""
146
147
148
+ if error_codes is None :
149
+ error_codes = []
150
+
147
151
def handle_exception (e ):
148
152
if hasattr (e , "error_code" ):
149
153
err_code = e .error_code
@@ -152,8 +156,12 @@ def handle_exception(e):
152
156
err_code = e .response ["Error" ]["Code" ]
153
157
err_msg = e .response ["Error" ]["Message" ]
154
158
155
- if i == num_retries or (error_codes != [] and err_code not in error_codes ):
156
- raise e
159
+ if err_code == "RequestLimitExceeded" :
160
+ return False
161
+
162
+ if error_codes and err_code not in error_codes :
163
+ return True
164
+
157
165
if logger is not None :
158
166
logger .log (
159
167
"got (possibly transient) EC2 error code '{0}': {1}. retrying..." .format (
@@ -162,44 +170,34 @@ def handle_exception(e):
162
170
)
163
171
164
172
def handle_boto3_exception (e ):
165
- if i == num_retries :
166
- raise e
167
- elif (
168
- error_codes != []
169
- and getattr (e , "response" , {}).get ("code" ) not in error_codes
170
- ):
171
- raise e
172
- elif logger is not None :
173
+ if error_codes and getattr (e , "response" , {}).get ("code" ) not in error_codes :
174
+ return True
175
+
176
+ if logger is not None :
173
177
if hasattr (e , "response" ):
174
178
logger .log (
175
179
"got (possibly transient) EC2 error '{}', retrying..." .format (
176
180
str (e .response ["Error" ])
177
181
)
178
182
)
179
183
184
+ def should_abort (e ):
185
+ if isinstance (e , (SQSError , EC2ResponseError , BotoServerError )):
186
+ return handle_exception (e )
187
+ elif isinstance (e , ClientError ):
188
+ return handle_boto3_exception (e )
189
+
180
190
i = 0
181
- num_retries = 7
182
191
while i <= num_retries :
183
192
i += 1
184
193
next_sleep = 5 + random .random () * (2 ** i )
185
194
186
195
try :
187
196
return f ()
188
- except EC2ResponseError as e :
189
- handle_exception (e )
190
- except SQSError as e :
191
- handle_exception (e )
192
- except ClientError as e :
193
- handle_boto3_exception (e )
194
- except BotoServerError as e :
195
- if e .error_code == "RequestLimitExceeded" :
196
- num_retries += 1
197
- else :
198
- handle_exception (e )
199
- except botocore .exceptions .ClientError as e :
200
- handle_exception (e )
201
197
except Exception as e :
202
- raise e
198
+ if num_retries == i or should_abort (e ):
199
+ raise e
200
+ num_retries += 1
203
201
204
202
time .sleep (next_sleep )
205
203
0 commit comments