134 lines
4.8 KiB
Python
134 lines
4.8 KiB
Python
# Copyright 2014 Baidu, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
|
# except in compliance with the License. You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software distributed under the
|
|
# License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
# either express or implied. See the License for the specific language governing permissions
|
|
# and limitations under the License.
|
|
|
|
"""
|
|
This module defines a common configuration class for BCE.
|
|
"""
|
|
|
|
import http.client
|
|
import logging
|
|
from builtins import str
|
|
from builtins import bytes
|
|
|
|
from baidubce.exception import BceServerError
|
|
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class NoRetryPolicy(object):
|
|
"""A policy that never retries."""
|
|
|
|
def should_retry(self, error, retries_attempted):
|
|
"""Always returns False.
|
|
|
|
:param error: ignored
|
|
:param retries_attempted: ignored
|
|
:return: always False
|
|
:rtype: bool
|
|
"""
|
|
return False
|
|
|
|
def get_delay_before_next_retry_in_millis(self, error, retries_attempted):
|
|
"""Always returns 0.
|
|
|
|
:param error: ignored
|
|
:param retries_attempted: ignored
|
|
:return: always 0
|
|
:rtype: int
|
|
"""
|
|
return 0
|
|
|
|
|
|
class BackOffRetryPolicy(object):
|
|
"""A policy that retries with exponential back-off strategy.
|
|
|
|
This policy will keep retrying until the maximum number of retries is reached. The delay time
|
|
will be a fixed interval for the first time then 2 * interval for the second, 4 * internal for
|
|
the third, and so on. In general, the delay time will be 2^number_of_retries_attempted*interval.
|
|
|
|
When a maximum of delay time is specified, the delay time will never exceed this limit.
|
|
"""
|
|
|
|
def __init__(self,
|
|
max_error_retry=3,
|
|
max_delay_in_millis=20 * 1000,
|
|
base_interval_in_millis=300):
|
|
"""
|
|
:param max_error_retry: the maximum number of retries.
|
|
:type max_error_retry: int
|
|
:param max_delay_in_millis: the maximum of delay time in milliseconds.
|
|
:type max_delay_in_millis: int
|
|
:param base_interval_in_millis: the base delay interval in milliseconds.
|
|
:type base_interval_in_millis: int
|
|
:raise ValueError if max_error_retry or max_delay_in_millis is negative.
|
|
"""
|
|
if max_error_retry < 0:
|
|
raise ValueError(b'max_error_retry should be a non-negative integer.')
|
|
if max_delay_in_millis < 0:
|
|
raise ValueError(b'max_delay_in_millis should be a non-negative integer.')
|
|
|
|
self.max_error_retry = max_error_retry
|
|
self.max_delay_in_millis = max_delay_in_millis
|
|
self.base_interval_in_millis = base_interval_in_millis
|
|
|
|
def should_retry(self, error, retries_attempted):
|
|
"""Return true if the http client should retry the request.
|
|
|
|
:param error: the caught error.
|
|
:type error: Exception
|
|
:param retries_attempted: the number of retries which has been attempted before.
|
|
:type retries_attempted: int
|
|
:return: true if the http client should retry the request.
|
|
:rtype: bool
|
|
"""
|
|
|
|
# stop retrying when the maximum number of retries is reached
|
|
if retries_attempted >= self.max_error_retry:
|
|
return False
|
|
|
|
# always retry on IOError
|
|
if isinstance(error, IOError):
|
|
_logger.debug(b'Retry for IOError.')
|
|
return True
|
|
|
|
# Only retry on a subset of service exceptions
|
|
if isinstance(error, BceServerError):
|
|
if error.status_code == http.client.INTERNAL_SERVER_ERROR:
|
|
_logger.debug(b'Retry for internal server error.')
|
|
return True
|
|
if error.status_code == http.client.SERVICE_UNAVAILABLE:
|
|
_logger.debug(b'Retry for service unavailable.')
|
|
return True
|
|
if error.code == BceServerError.REQUEST_EXPIRED:
|
|
_logger.debug(b'Retry for request expired.')
|
|
return True
|
|
|
|
return False
|
|
|
|
def get_delay_before_next_retry_in_millis(self, error, retries_attempted):
|
|
"""Returns the delay time in milliseconds before the next retry.
|
|
|
|
:param error: the caught error.
|
|
:type error: Exception
|
|
:param retries_attempted: the number of retries which has been attempted before.
|
|
:type retries_attempted: int
|
|
:return: the delay time in milliseconds before the next retry.
|
|
:rtype: int
|
|
"""
|
|
if retries_attempted < 0:
|
|
return 0
|
|
delay_in_millis = (1 << retries_attempted) * self.base_interval_in_millis
|
|
if delay_in_millis > self.max_delay_in_millis:
|
|
return self.max_delay_in_millis
|
|
return delay_in_millis
|