Skip to content

Commit a61fd35

Browse files
committed
code update
1 parent 028fb69 commit a61fd35

File tree

4 files changed

+91
-35
lines changed

4 files changed

+91
-35
lines changed

aliyun-python-sdk-core/aliyunsdkcore/client.py

Lines changed: 72 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# under the License.
1919

2020
# coding=utf-8
21+
import time
2122
import warnings
2223
import json
2324
import aliyunsdkcore
@@ -35,7 +36,9 @@
3536

3637
from aliyunsdkcore.endpoint.resolver_endpoint_request import ResolveEndpointRequest
3738
from aliyunsdkcore.endpoint.default_endpoint_resolver import DefaultEndpointResolver
38-
39+
import aliyunsdkcore.retry.retry_policy as retry_policy
40+
from aliyunsdkcore.retry.retry_condition import RetryCondition
41+
from aliyunsdkcore.retry.retry_policy_context import RetryPolicyContext
3942

4043
"""
4144
Acs default client module.
@@ -52,7 +55,7 @@ def __init__(
5255
secret=None,
5356
region_id="cn-hangzhou",
5457
auto_retry=True,
55-
max_retry_time=3,
58+
max_retry_time=None,
5659
user_agent=None,
5760
port=80,
5861
timeout=DEFAULT_SDK_CONNECTION_TIMEOUT_IN_SECONDS,
@@ -71,12 +74,12 @@ def __init__(
7174
:return:
7275
"""
7376

74-
self.__max_retry_num = max_retry_time
75-
self.__auto_retry = auto_retry
76-
self.__ak = ak
77-
self.__secret = secret
78-
self.__region_id = region_id
79-
self.__user_agent = user_agent
77+
self._max_retry_num = max_retry_time
78+
self._auto_retry = auto_retry
79+
self._ak = ak
80+
self._secret = secret
81+
self._region_id = region_id
82+
self._user_agent = user_agent
8083
self._port = port
8184
self._timeout = timeout
8285
credential = {
@@ -91,6 +94,13 @@ def __init__(
9194
credential, region_id, self.implementation_of_do_action, debug)
9295
self._endpoint_resolver = DefaultEndpointResolver(self)
9396

97+
if self._auto_retry:
98+
self._retry_policy = retry_policy.PREDEFINED_DEFAULT_RETRY_POLICY
99+
if self._max_retry_num:
100+
self._retry_policy.max_retry_times = self._max_retry_num
101+
else:
102+
self._retry_policy = retry_policy.NO_RETRY_POLICY
103+
94104
def get_region_id(self):
95105
return self.__region_id
96106

@@ -189,12 +199,40 @@ def implementation_of_do_action(self, request, signer=None):
189199
else:
190200
endpoint = self._resolve_endpoint(request)
191201

202+
return self._handle_retry_and_timeout(endpoint, request, signer)
203+
204+
def _add_request_client_token(self, request):
205+
if hasattr(request, "set_ClientToken"):
206+
207+
208+
def _handle_retry_and_timeout(self, endpoint, request, signer):
209+
# it's a temporary implement. the long-term plan will be a group a normalized handlers
210+
# which contains retry_handler and timeout_handler
211+
retryable = RetryCondition.SHOULD_RETRY
212+
retries = 0
213+
while retryable & RetryCondition.SHOULD_RETRY:
214+
215+
if retryable & RetryCondition.SHOULD_RETRY_WITH_CLIENT_TOKEN:
216+
self._add_request_client_token(request)
217+
218+
status, headers, body, exception = self._handle_single_request(endpoint,
219+
request,
220+
signer)
221+
retry_policy_context = RetryPolicyContext(request, exception, retries, status)
222+
retryable = self._retry_policy.should_retry(retry_policy_context)
223+
retry_policy_context.retryable = retryable
224+
time_to_sleep = self._retry_policy.compute_delay_before_next_retry(retry_policy_context)
225+
time.sleep(time_to_sleep / 1000.0)
226+
retries += 1
227+
228+
def _handle_single_request(self, endpoint, request, signer):
192229
http_response = self._make_http_response(endpoint, request, signer)
193230

231+
exception = None
232+
194233
# Do the actual network thing
195234
try:
196235
status, headers, body = http_response.get_response_object()
197-
return status, headers, body
198236
except IOError as e:
199237
error_message = str(e)
200238
error_message += "\nEndpoint: " + endpoint
@@ -204,7 +242,11 @@ def implementation_of_do_action(self, request, signer=None):
204242
error_message += "\nHttpHeaders: " + \
205243
str(http_response.get_headers())
206244

207-
raise ClientException(error_code.SDK_HTTP_ERROR, error_message)
245+
exception = ClientException(error_code.SDK_HTTP_ERROR, error_message)
246+
return None, None, None, exception
247+
248+
exception = self._get_server_exception(status, body)
249+
return status, headers, body, exception
208250

209251
@staticmethod
210252
def _parse_error_info_from_response_body(response_body):
@@ -223,34 +265,38 @@ def _parse_error_info_from_response_body(response_body):
223265

224266
return error_code_to_return, error_message_to_return
225267

226-
def do_action_with_exception(self, acs_request):
227-
228-
# set server response format as json, because this function will
229-
# parse the response so which format doesn't matter
230-
acs_request.set_accept_format('JSON')
231-
232-
status, headers, body = self.implementation_of_do_action(acs_request)
233-
268+
def _get_server_exception(self, http_status, response_body):
234269
request_id = None
235270

236271
try:
237-
body_obj = json.loads(body.decode('utf-8'))
272+
body_obj = json.loads(response_body.decode('utf-8'))
238273
request_id = body_obj.get('RequestId')
239274
except (ValueError, TypeError, AttributeError):
240275
# in case the response body is not a json string, return the raw
241276
# data instead
242277
pass
243278

244-
if status < http_client.OK or status >= http_client.MULTIPLE_CHOICES:
279+
if http_status < http_client.OK or http_status >= http_client.MULTIPLE_CHOICES:
245280

246281
server_error_code, server_error_message = self._parse_error_info_from_response_body(
247-
body.decode('utf-8'))
248-
raise ServerException(
282+
response_body.decode('utf-8'))
283+
return ServerException(
249284
server_error_code,
250285
server_error_message,
251-
http_status=status,
286+
http_status=http_status,
252287
request_id=request_id)
253288

289+
def do_action_with_exception(self, acs_request):
290+
291+
# set server response format as json, because this function will
292+
# parse the response so which format doesn't matter
293+
acs_request.set_accept_format('JSON')
294+
295+
status, headers, body, exception = self.implementation_of_do_action(acs_request)
296+
297+
if exception:
298+
raise exception
299+
254300
return body
255301

256302
def _resolve_endpoint(self, request):
@@ -266,11 +312,12 @@ def do_action(self, acs_request):
266312
warnings.warn(
267313
"do_action() method is deprecated, please use do_action_with_exception() instead.",
268314
DeprecationWarning)
269-
status, headers, body = self.implementation_of_do_action(acs_request)
315+
status, headers, body, exception = self.implementation_of_do_action(acs_request)
270316
return body
271317

272318
def get_response(self, acs_request):
273-
return self.implementation_of_do_action(acs_request)
319+
status, headers, body, exception = self.implementation_of_do_action(acs_request)
320+
return status, headers, body
274321

275322
def add_endpoint(self, region_id, product_code, endpoint):
276323
self._endpoint_resolver.put_endpoint_entry(

aliyun-python-sdk-core/aliyunsdkcore/endpoint/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
# under the License.
1717
#
1818

19+
from abc import ABCMeta, abstractmethod
1920

20-
class EndpointResolver(object):
21+
22+
class EndpointResolver(metaclass=ABCMeta):
2123

2224
def resolve(self, request):
2325
pass

aliyun-python-sdk-core/aliyunsdkcore/retry/backoff_strategy.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
# limitations under the License.
1414

1515
import random
16+
from abc import ABCMeta, abstractmethod
1617

1718
from aliyunsdkcore.retry.retry_condition import RetryCondition
1819

1920

20-
class BackoffStrategy:
21+
class BackoffStrategy(metaclass=ABCMeta):
2122

23+
@abstractmethod
2224
def compute_delay_before_next_retry(self, retry_policy_context):
2325
"""Compute delay for request need to be retried, in milliseconds"""
2426
pass

aliyun-python-sdk-core/aliyunsdkcore/retry/retry_condition.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import jmespath
16+
from abc import ABCMeta, abstractmethod
1617

1718
import aliyunsdkcore.utils
1819
import aliyunsdkcore.utils.validation as validation
@@ -27,17 +28,18 @@ def _find_data_in_retry_config(key_name, request, retry_config):
2728
return jmespath.search(path, retry_config)
2829

2930

30-
class RetryCondition:
31+
class RetryCondition(metaclass=ABCMeta):
3132

3233
BLANK_STATUS = 0
3334
NO_RETRY = 1
3435
SHOULD_RETRY = 2
3536
SHOULD_RETRY_WITH_CLIENT_TOKEN = 4
3637
SHOULD_RETRY_WITH_THROTTLING_BACKOFF = 8
3738

39+
@abstractmethod
3840
def should_retry(self, retry_policy_context):
3941
"""Decide whether the previous request should be retried."""
40-
return RetryCondition.NO_RETRY
42+
pass
4143

4244

4345
class NoRetryCondition(RetryCondition):
@@ -46,7 +48,7 @@ def should_retry(self, retry_policy_context):
4648
return RetryCondition.NO_RETRY
4749

4850

49-
class MaxRetryTimesCondition:
51+
class MaxRetryTimesCondition(RetryCondition):
5052

5153
def __init__(self, max_retry_times):
5254
validation.assert_integer_positive(max_retry_times, "max_retry_times")
@@ -59,7 +61,7 @@ def should_retry(self, retry_policy_context):
5961
return RetryCondition.NO_RETRY
6062

6163

62-
class RetryOnExceptionCondition:
64+
class RetryOnExceptionCondition(RetryCondition):
6365

6466
def __init__(self, retry_config):
6567
self.retry_config = retry_config
@@ -119,7 +121,7 @@ def _should_retry_with_client_token(self, retry_policy_context):
119121
return RetryCondition.BLANK_STATUS
120122

121123

122-
class ChainedRetryCondition:
124+
class ChainedRetryCondition(RetryCondition):
123125

124126
def __init__(self, retry_condition_chain):
125127
self.retry_condition_chain = retry_condition_chain
@@ -131,7 +133,7 @@ def should_retry(self, retry_policy_context):
131133
return retryable
132134

133135

134-
class MixedRetryCondition:
136+
class MixedRetryCondition(RetryCondition):
135137

136138
def __init__(self, max_retry_times, retry_config):
137139
self._retry_condition_chain = ChainedRetryCondition([
@@ -148,7 +150,10 @@ class DefaultConfigRetryCondition(MixedRetryCondition):
148150

149151
MAX_RETRY_TIMES = 3
150152
RETRY_CONFIG_FILE = "retry_config.json"
153+
_loaded_retry_config = None
151154

152155
def __init__(self):
153-
retry_config = aliyunsdkcore.utils._load_json_from_data_dir(self.RETRY_CONFIG_FILE)
154-
MixedRetryCondition.__init__(self, self.MAX_RETRY_TIMES, retry_config)
156+
if not self._loaded_retry_config:
157+
self._loaded_retry_config = aliyunsdkcore.utils._load_json_from_data_dir(
158+
self.RETRY_CONFIG_FILE)
159+
MixedRetryCondition.__init__(self, self.MAX_RETRY_TIMES, self._loaded_retry_config)

0 commit comments

Comments
 (0)