Skip to content

Commit a98bd20

Browse files
authored
refactor hierarchy of HttpPolicy & AsyncHttpPolicy (Azure#15831)
* refactor hierarchy of HttpPolicy & AsyncHttpPolicy
1 parent 9376c2f commit a98bd20

File tree

4 files changed

+109
-110
lines changed

4 files changed

+109
-110
lines changed

sdk/core/azure-core/azure/core/pipeline/policies/_redirect.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,7 @@
4141

4242
_LOGGER = logging.getLogger(__name__)
4343

44-
45-
class RedirectPolicy(HTTPPolicy):
46-
"""A redirect policy.
47-
48-
A redirect policy in the pipeline can be configured directly or per operation.
49-
50-
:keyword bool permit_redirects: Whether the client allows redirects. Defaults to True.
51-
:keyword int redirect_max: The maximum allowed redirects. Defaults to 30.
52-
53-
.. admonition:: Example:
54-
55-
.. literalinclude:: ../samples/test_example_sync.py
56-
:start-after: [START redirect_policy]
57-
:end-before: [END redirect_policy]
58-
:language: python
59-
:dedent: 4
60-
:caption: Configuring a redirect policy.
61-
"""
44+
class RedirectPolicyBase(object):
6245

6346
REDIRECT_STATUSES = frozenset([300, 301, 302, 303, 307, 308])
6447

@@ -72,7 +55,7 @@ def __init__(self, **kwargs):
7255
self._remove_headers_on_redirect = remove_headers.union(self.REDIRECT_HEADERS_BLACKLIST)
7356
redirect_status = set(kwargs.get('redirect_on_status_codes', []))
7457
self._redirect_on_status_codes = redirect_status.union(self.REDIRECT_STATUSES)
75-
super(RedirectPolicy, self).__init__()
58+
super(RedirectPolicyBase, self).__init__()
7659

7760
@classmethod
7861
def no_redirects(cls):
@@ -141,6 +124,24 @@ def increment(self, settings, response, redirect_location):
141124
response.http_request.headers.pop(non_redirect_header, None)
142125
return settings['redirects'] >= 0
143126

127+
class RedirectPolicy(RedirectPolicyBase, HTTPPolicy):
128+
"""A redirect policy.
129+
130+
A redirect policy in the pipeline can be configured directly or per operation.
131+
132+
:keyword bool permit_redirects: Whether the client allows redirects. Defaults to True.
133+
:keyword int redirect_max: The maximum allowed redirects. Defaults to 30.
134+
135+
.. admonition:: Example:
136+
137+
.. literalinclude:: ../samples/test_example_sync.py
138+
:start-after: [START redirect_policy]
139+
:end-before: [END redirect_policy]
140+
:language: python
141+
:dedent: 4
142+
:caption: Configuring a redirect policy.
143+
"""
144+
144145
def send(self, request):
145146
"""Sends the PipelineRequest object to the next policy.
146147
Uses redirect settings to send request to redirect endpoint if necessary.

sdk/core/azure-core/azure/core/pipeline/policies/_redirect_async.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727

2828
from azure.core.exceptions import TooManyRedirectsError
2929
from . import AsyncHTTPPolicy
30-
from ._redirect import RedirectPolicy
30+
from ._redirect import RedirectPolicyBase
3131

3232

33-
class AsyncRedirectPolicy(RedirectPolicy, AsyncHTTPPolicy):
33+
class AsyncRedirectPolicy(RedirectPolicyBase, AsyncHTTPPolicy):
3434
"""An async redirect policy.
3535
3636
An async redirect policy in the pipeline can be configured directly or per operation.

sdk/core/azure-core/azure/core/pipeline/policies/_retry.py

Lines changed: 85 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -53,49 +53,8 @@ class RetryMode(str, Enum):
5353
Exponential = 'exponential'
5454
Fixed = 'fixed'
5555

56-
class RetryPolicy(HTTPPolicy):
57-
"""A retry policy.
58-
59-
The retry policy in the pipeline can be configured directly, or tweaked on a per-call basis.
60-
61-
:keyword int retry_total: Total number of retries to allow. Takes precedence over other counts.
62-
Default value is 10.
63-
64-
:keyword int retry_connect: How many connection-related errors to retry on.
65-
These are errors raised before the request is sent to the remote server,
66-
which we assume has not triggered the server to process the request. Default value is 3.
67-
68-
:keyword int retry_read: How many times to retry on read errors.
69-
These errors are raised after the request was sent to the server, so the
70-
request may have side-effects. Default value is 3.
71-
72-
:keyword int retry_status: How many times to retry on bad status codes. Default value is 3.
73-
74-
:keyword float retry_backoff_factor: A backoff factor to apply between attempts after the second try
75-
(most errors are resolved immediately by a second try without a delay).
76-
In fixed mode, retry policy will alwasy sleep for {backoff factor}.
77-
In 'exponential' mode, retry policy will sleep for: `{backoff factor} * (2 ** ({number of total retries} - 1))`
78-
seconds. If the backoff_factor is 0.1, then the retry will sleep
79-
for [0.0s, 0.2s, 0.4s, ...] between retries. The default value is 0.8.
80-
81-
:keyword int retry_backoff_max: The maximum back off time. Default value is 120 seconds (2 minutes).
82-
83-
:keyword RetryMode retry_mode: Fixed or exponential delay between attemps, default is exponential.
84-
85-
:keyword int timeout: Timeout setting for the operation in seconds, default is 604800s (7 days).
86-
87-
.. admonition:: Example:
88-
89-
.. literalinclude:: ../samples/test_example_sync.py
90-
:start-after: [START retry_policy]
91-
:end-before: [END retry_policy]
92-
:language: python
93-
:dedent: 4
94-
:caption: Configuring a retry policy.
95-
"""
96-
56+
class RetryPolicyBase(object):
9757
# pylint: disable=too-many-instance-attributes
98-
9958
#: Maximum backoff time.
10059
BACKOFF_MAX = 120
10160
_SAFE_CODES = set(range(506)) - set([408, 429, 500, 502, 503, 504])
@@ -116,7 +75,7 @@ def __init__(self, **kwargs):
11675
self._retry_on_status_codes = set(status_codes) | retry_codes
11776
self._method_whitelist = frozenset(['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'])
11877
self._respect_retry_after_header = True
119-
super(RetryPolicy, self).__init__()
78+
super(RetryPolicyBase, self).__init__()
12079

12180
@classmethod
12281
def no_retries(cls):
@@ -179,49 +138,6 @@ def get_retry_after(self, response):
179138
"""
180139
return _utils.get_retry_after(response)
181140

182-
def _sleep_for_retry(self, response, transport):
183-
"""Sleep based on the Retry-After response header value.
184-
185-
:param response: The PipelineResponse object.
186-
:type response: ~azure.core.pipeline.PipelineResponse
187-
:param transport: The HTTP transport type.
188-
"""
189-
retry_after = self.get_retry_after(response)
190-
if retry_after:
191-
transport.sleep(retry_after)
192-
return True
193-
return False
194-
195-
def _sleep_backoff(self, settings, transport):
196-
"""Sleep using exponential backoff. Immediately returns if backoff is 0.
197-
198-
:param dict settings: The retry settings.
199-
:param transport: The HTTP transport type.
200-
"""
201-
backoff = self.get_backoff_time(settings)
202-
if backoff <= 0:
203-
return
204-
transport.sleep(backoff)
205-
206-
def sleep(self, settings, transport, response=None):
207-
"""Sleep between retry attempts.
208-
209-
This method will respect a server's ``Retry-After`` response header
210-
and sleep the duration of the time requested. If that is not present, it
211-
will use an exponential backoff. By default, the backoff factor is 0 and
212-
this method will return immediately.
213-
214-
:param dict settings: The retry settings.
215-
:param transport: The HTTP transport type.
216-
:param response: The PipelineResponse object.
217-
:type response: ~azure.core.pipeline.PipelineResponse
218-
"""
219-
if response:
220-
slept = self._sleep_for_retry(response, transport)
221-
if slept:
222-
return
223-
self._sleep_backoff(settings, transport)
224-
225141
def _is_connection_error(self, err):
226142
"""Errors when we're fairly sure that the server did not receive the
227143
request, so it should be safe to retry.
@@ -411,6 +327,89 @@ def _configure_positions(self, request, retry_settings):
411327
retry_settings['body_position'] = body_position
412328
retry_settings['file_positions'] = file_positions
413329

330+
class RetryPolicy(RetryPolicyBase, HTTPPolicy):
331+
"""A retry policy.
332+
333+
The retry policy in the pipeline can be configured directly, or tweaked on a per-call basis.
334+
335+
:keyword int retry_total: Total number of retries to allow. Takes precedence over other counts.
336+
Default value is 10.
337+
338+
:keyword int retry_connect: How many connection-related errors to retry on.
339+
These are errors raised before the request is sent to the remote server,
340+
which we assume has not triggered the server to process the request. Default value is 3.
341+
342+
:keyword int retry_read: How many times to retry on read errors.
343+
These errors are raised after the request was sent to the server, so the
344+
request may have side-effects. Default value is 3.
345+
346+
:keyword int retry_status: How many times to retry on bad status codes. Default value is 3.
347+
348+
:keyword float retry_backoff_factor: A backoff factor to apply between attempts after the second try
349+
(most errors are resolved immediately by a second try without a delay).
350+
In fixed mode, retry policy will alwasy sleep for {backoff factor}.
351+
In 'exponential' mode, retry policy will sleep for: `{backoff factor} * (2 ** ({number of total retries} - 1))`
352+
seconds. If the backoff_factor is 0.1, then the retry will sleep
353+
for [0.0s, 0.2s, 0.4s, ...] between retries. The default value is 0.8.
354+
355+
:keyword int retry_backoff_max: The maximum back off time. Default value is 120 seconds (2 minutes).
356+
357+
:keyword RetryMode retry_mode: Fixed or exponential delay between attemps, default is exponential.
358+
359+
:keyword int timeout: Timeout setting for the operation in seconds, default is 604800s (7 days).
360+
361+
.. admonition:: Example:
362+
363+
.. literalinclude:: ../samples/test_example_sync.py
364+
:start-after: [START retry_policy]
365+
:end-before: [END retry_policy]
366+
:language: python
367+
:dedent: 4
368+
:caption: Configuring a retry policy.
369+
"""
370+
def _sleep_for_retry(self, response, transport):
371+
"""Sleep based on the Retry-After response header value.
372+
373+
:param response: The PipelineResponse object.
374+
:type response: ~azure.core.pipeline.PipelineResponse
375+
:param transport: The HTTP transport type.
376+
"""
377+
retry_after = self.get_retry_after(response)
378+
if retry_after:
379+
transport.sleep(retry_after)
380+
return True
381+
return False
382+
383+
def _sleep_backoff(self, settings, transport):
384+
"""Sleep using exponential backoff. Immediately returns if backoff is 0.
385+
386+
:param dict settings: The retry settings.
387+
:param transport: The HTTP transport type.
388+
"""
389+
backoff = self.get_backoff_time(settings)
390+
if backoff <= 0:
391+
return
392+
transport.sleep(backoff)
393+
394+
def sleep(self, settings, transport, response=None):
395+
"""Sleep between retry attempts.
396+
397+
This method will respect a server's ``Retry-After`` response header
398+
and sleep the duration of the time requested. If that is not present, it
399+
will use an exponential backoff. By default, the backoff factor is 0 and
400+
this method will return immediately.
401+
402+
:param dict settings: The retry settings.
403+
:param transport: The HTTP transport type.
404+
:param response: The PipelineResponse object.
405+
:type response: ~azure.core.pipeline.PipelineResponse
406+
"""
407+
if response:
408+
slept = self._sleep_for_retry(response, transport)
409+
if slept:
410+
return
411+
self._sleep_backoff(settings, transport)
412+
414413
def send(self, request):
415414
"""Sends the PipelineRequest object to the next policy. Uses retry settings if necessary.
416415

sdk/core/azure-core/azure/core/pipeline/policies/_retry_async.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,14 @@
3636
ClientAuthenticationError,
3737
ServiceRequestError,
3838
)
39-
from ._base import HTTPPolicy
4039
from ._base_async import AsyncHTTPPolicy
41-
from ._retry import RetryPolicy
40+
from ._retry import RetryPolicyBase
4241

4342
_LOGGER = logging.getLogger(__name__)
4443

4544

4645

47-
class AsyncRetryPolicy(RetryPolicy, AsyncHTTPPolicy):
46+
class AsyncRetryPolicy(RetryPolicyBase, AsyncHTTPPolicy):
4847
"""Async flavor of the retry policy.
4948
5049
The async retry policy in the pipeline can be configured directly, or tweaked on a per-call basis.

0 commit comments

Comments
 (0)