1 from __future__ import absolute_import
5 from ..exceptions import (
12 from ..packages import six
15 log = logging.getLogger(__name__)
19 """ Retry configuration.
21 Each retry attempt will create a new Retry object with updated values, so
22 they can be safely reused.
24 Retries can be defined as a default for a pool::
26 retries = Retry(connect=5, read=2, redirect=5)
27 http = PoolManager(retries=retries)
28 response = http.request('GET', 'http://example.com/')
30 Or per-request (which overrides the default for the pool)::
32 response = http.request('GET', 'http://example.com/', retries=Retry(10))
34 Retries can be disabled by passing ``False``::
36 response = http.request('GET', 'http://example.com/', retries=False)
38 Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless
39 retries are disabled, in which case the causing exception will be raised.
42 Total number of retries to allow. Takes precedence over other counts.
44 Set to ``None`` to remove this constraint and fall back on other
45 counts. It's a good idea to set this to some sensibly-high value to
46 account for unexpected edge cases and avoid infinite retry loops.
48 Set to ``0`` to fail on the first retry.
50 Set to ``False`` to disable and imply ``raise_on_redirect=False``.
53 How many connection-related errors to retry on.
55 These are errors raised before the request is sent to the remote server,
56 which we assume has not triggered the server to process the request.
58 Set to ``0`` to fail on the first retry of this type.
61 How many times to retry on read errors.
63 These errors are raised after the request was sent to the server, so the
64 request may have side-effects.
66 Set to ``0`` to fail on the first retry of this type.
69 How many redirects to perform. Limit this to avoid infinite redirect
72 A redirect is a HTTP response with a status code 301, 302, 303, 307 or
75 Set to ``0`` to fail on the first retry of this type.
77 Set to ``False`` to disable and imply ``raise_on_redirect=False``.
79 :param iterable method_whitelist:
80 Set of uppercased HTTP method verbs that we should retry on.
82 By default, we only retry on methods which are considered to be
83 indempotent (multiple requests with the same parameters end with the
84 same state). See :attr:`Retry.DEFAULT_METHOD_WHITELIST`.
86 :param iterable status_forcelist:
87 A set of HTTP status codes that we should force a retry on.
89 By default, this is disabled with ``None``.
91 :param float backoff_factor:
92 A backoff factor to apply between attempts. urllib3 will sleep for::
94 {backoff factor} * (2 ^ ({number of total retries} - 1))
96 seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep
97 for [0.1s, 0.2s, 0.4s, ...] between retries. It will never be longer
98 than :attr:`Retry.BACKOFF_MAX`.
100 By default, backoff is disabled (set to 0).
102 :param bool raise_on_redirect: Whether, if the number of redirects is
103 exhausted, to raise a MaxRetryError, or to return a response with a
104 response code in the 3xx range.
106 :param bool raise_on_status: Similar meaning to ``raise_on_redirect``:
107 whether we should raise an exception, or return a response,
108 if status falls in ``status_forcelist`` range and retries have
112 DEFAULT_METHOD_WHITELIST = frozenset([
113 'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'])
115 #: Maximum backoff time.
118 def __init__(self, total=10, connect=None, read=None, redirect=None,
119 method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None,
120 backoff_factor=0, raise_on_redirect=True, raise_on_status=True,
124 self.connect = connect
127 if redirect is False or total is False:
129 raise_on_redirect = False
131 self.redirect = redirect
132 self.status_forcelist = status_forcelist or set()
133 self.method_whitelist = method_whitelist
134 self.backoff_factor = backoff_factor
135 self.raise_on_redirect = raise_on_redirect
136 self.raise_on_status = raise_on_status
137 self._observed_errors = _observed_errors # TODO: use .history instead?
142 connect=self.connect, read=self.read, redirect=self.redirect,
143 method_whitelist=self.method_whitelist,
144 status_forcelist=self.status_forcelist,
145 backoff_factor=self.backoff_factor,
146 raise_on_redirect=self.raise_on_redirect,
147 raise_on_status=self.raise_on_status,
148 _observed_errors=self._observed_errors,
151 return type(self)(**params)
154 def from_int(cls, retries, redirect=True, default=None):
155 """ Backwards-compatibility for the old retries format."""
157 retries = default if default is not None else cls.DEFAULT
159 if isinstance(retries, Retry):
162 redirect = bool(redirect) and None
163 new_retries = cls(retries, redirect=redirect)
164 log.debug("Converted retries value: %r -> %r", retries, new_retries)
167 def get_backoff_time(self):
168 """ Formula for computing the current backoff
172 if self._observed_errors <= 1:
175 backoff_value = self.backoff_factor * (2 ** (self._observed_errors - 1))
176 return min(self.BACKOFF_MAX, backoff_value)
179 """ Sleep between retry attempts using an exponential backoff.
181 By default, the backoff factor is 0 and this method will return
184 backoff = self.get_backoff_time()
189 def _is_connection_error(self, err):
190 """ Errors when we're fairly sure that the server did not receive the
191 request, so it should be safe to retry.
193 return isinstance(err, ConnectTimeoutError)
195 def _is_read_error(self, err):
196 """ Errors that occur after the request has been started, so we should
197 assume that the server began processing it.
199 return isinstance(err, (ReadTimeoutError, ProtocolError))
201 def is_forced_retry(self, method, status_code):
202 """ Is this method/status code retryable? (Based on method/codes whitelists)
204 if self.method_whitelist and method.upper() not in self.method_whitelist:
207 return self.status_forcelist and status_code in self.status_forcelist
209 def is_exhausted(self):
210 """ Are we out of retries? """
211 retry_counts = (self.total, self.connect, self.read, self.redirect)
212 retry_counts = list(filter(None, retry_counts))
216 return min(retry_counts) < 0
218 def increment(self, method=None, url=None, response=None, error=None,
219 _pool=None, _stacktrace=None):
220 """ Return a new Retry object with incremented retry counters.
222 :param response: A response object, or None, if the server did not
224 :type response: :class:`~urllib3.response.HTTPResponse`
225 :param Exception error: An error encountered during the request, or
226 None if the response was received successfully.
228 :return: A new ``Retry`` object.
230 if self.total is False and error:
231 # Disabled, indicate to re-raise the error.
232 raise six.reraise(type(error), error, _stacktrace)
235 if total is not None:
238 _observed_errors = self._observed_errors
239 connect = self.connect
241 redirect = self.redirect
244 if error and self._is_connection_error(error):
247 raise six.reraise(type(error), error, _stacktrace)
248 elif connect is not None:
250 _observed_errors += 1
252 elif error and self._is_read_error(error):
255 raise six.reraise(type(error), error, _stacktrace)
256 elif read is not None:
258 _observed_errors += 1
260 elif response and response.get_redirect_location():
262 if redirect is not None:
264 cause = 'too many redirects'
267 # Incrementing because of a server error like a 500 in
268 # status_forcelist and a the given method is in the whitelist
269 _observed_errors += 1
270 cause = ResponseError.GENERIC_ERROR
271 if response and response.status:
272 cause = ResponseError.SPECIFIC_ERROR.format(
273 status_code=response.status)
275 new_retry = self.new(
277 connect=connect, read=read, redirect=redirect,
278 _observed_errors=_observed_errors)
280 if new_retry.is_exhausted():
281 raise MaxRetryError(_pool, url, error or ResponseError(cause))
283 log.debug("Incremented Retry for (url='%s'): %r", url, new_retry)
288 return ('{cls.__name__}(total={self.total}, connect={self.connect}, '
289 'read={self.read}, redirect={self.redirect})').format(
290 cls=type(self), self=self)
293 # For backwards compatibility (equivalent to pre-v1.9):
294 Retry.DEFAULT = Retry(3)