Skip to content

Add support for retry of HTTP requests #1384

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 63 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
0d92d13
add retry and its configs
HantingZhang2 Mar 16, 2023
d21460d
auto reformat
HantingZhang2 Mar 16, 2023
c048168
format
HantingZhang2 Mar 16, 2023
1121456
redo is_retry and rewrite retry config options
HantingZhang2 Mar 17, 2023
5a777f9
Reformat
HantingZhang2 Mar 17, 2023
880aa66
Merge branch 'master' into add-retry
HantingZhang2 Mar 17, 2023
7c7850e
Merge branch 'master' into add-retry
HantingZhang2 Apr 13, 2023
65d4d12
Merge branch 'master' into add-retry
HantingZhang2 Apr 13, 2023
e37f6eb
Merge branch 'master' into add-retry
HantingZhang2 Jul 17, 2023
b17980a
Fix syntax & add test
HantingZhang2 Jul 17, 2023
1f4fdc5
Fixe test & adjusting retry impl
HantingZhang2 Jul 18, 2023
5d08134
Merge branch 'master' into add-retry
HantingZhang2 Jul 18, 2023
0dcefe3
Merge branch 'master' into add-retry
HantingZhang2 Jul 18, 2023
9bc5d38
pre-commit fixes
Jul 18, 2023
f219250
Update template
HantingZhang2 Jul 18, 2023
1775ef5
Fix import
HantingZhang2 Jul 19, 2023
b1be7d7
Merge branch 'add-retry' of github.com:DataDog/datadog-api-client-pyt…
HantingZhang2 Jul 19, 2023
0e16b42
pre-commit fixes
Jul 19, 2023
ac76aea
change retry import
HantingZhang2 Jul 19, 2023
008c424
Merge branch 'add-retry' of github.com:DataDog/datadog-api-client-pyt…
HantingZhang2 Jul 19, 2023
e35f6f8
remove retry import
HantingZhang2 Jul 19, 2023
4633c02
remove saving content of the response
HantingZhang2 Jul 19, 2023
439c4c1
update cassette
HantingZhang2 Jul 19, 2023
766c910
delete env file
HantingZhang2 Jul 19, 2023
4a00cee
update cassette
HantingZhang2 Jul 19, 2023
9200464
use mock for test_retry
HantingZhang2 Jul 20, 2023
25dae16
pre-commit fixes
Jul 20, 2023
1eb644d
use urllib3 for requests
HantingZhang2 Jul 20, 2023
1fb39bc
Merge branch 'add-retry' of github.com:DataDog/datadog-api-client-pyt…
HantingZhang2 Jul 20, 2023
c8c3158
pre-commit fixes
Jul 20, 2023
5f8a5d6
fix return format
HantingZhang2 Jul 20, 2023
1fe71ba
Merge branch 'add-retry' of github.com:DataDog/datadog-api-client-pyt…
HantingZhang2 Jul 20, 2023
4020b2b
pre-commit fixes
Jul 20, 2023
7a8aa03
add response header
HantingZhang2 Jul 20, 2023
46d2e15
Merge branch 'add-retry' of github.com:DataDog/datadog-api-client-pyt…
HantingZhang2 Jul 20, 2023
23d9f07
pre-commit fixes
Jul 20, 2023
0c35222
change retry test
HantingZhang2 Jul 20, 2023
c9cd884
Merge branch 'add-retry' of github.com:DataDog/datadog-api-client-pyt…
HantingZhang2 Jul 20, 2023
a607a71
Merge branch 'master' into add-retry
HantingZhang2 Jul 20, 2023
e704edb
pre-commit fixes
Jul 20, 2023
2a53f89
update test_retry
HantingZhang2 Jul 21, 2023
740686b
Merge branch 'master' into add-retry
HantingZhang2 Jul 21, 2023
5d69334
pre-commit fixes
Jul 21, 2023
f0215a2
use call count
HantingZhang2 Jul 21, 2023
66b5e1b
Merge branch 'add-retry' of github.com:DataDog/datadog-api-client-pyt…
HantingZhang2 Jul 21, 2023
4e18200
pre-commit fixes
Jul 21, 2023
3c3e93d
Merge branch 'master' into add-retry
HantingZhang2 Jul 24, 2023
33c355b
Update .generator/src/generator/templates/rest.j2
HantingZhang2 Jul 24, 2023
d9d14a6
pre-commit fixes
Jul 24, 2023
c3ea131
Add back test
therve Jul 24, 2023
0a682b2
pre-commit fixes
Jul 24, 2023
2b32582
Fix content encoding
therve Jul 24, 2023
43568c7
touch up rest client and test
HantingZhang2 Jul 24, 2023
e6f2c6f
pre-commit fixes
Jul 24, 2023
1bdf16b
add test without reset header
HantingZhang2 Jul 24, 2023
d593542
pre-commit fixes
Jul 24, 2023
5f4c72f
change allowed method check
HantingZhang2 Jul 24, 2023
9cae414
Merge branch 'add-retry' of github.com:DataDog/datadog-api-client-pyt…
HantingZhang2 Jul 24, 2023
f87b416
Merge branch 'master' into add-retry
HantingZhang2 Jul 24, 2023
17637a4
Minor tweaks
therve Jul 25, 2023
6d7c644
Use cassette for errors as well
therve Jul 25, 2023
42c2f1b
Merge branch 'master' into add-retry
therve Jul 25, 2023
f67b93f
Docs
therve Jul 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .generator/src/generator/templates/configuration.j2
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ JSON_SCHEMA_VALIDATION_KEYWORDS = {
"minItems",
}


class _UnstableOperations:

def __init__(self, values):
Expand Down Expand Up @@ -158,6 +157,9 @@ class Configuration:
check_input_type=True,
check_return_type=True,
spec_property_naming=False,
enable_retry= False,
retry_backoff_factor= 2,
max_retries= 3,
):
"""Constructor."""
self._base_path = "https://api.datadoghq.com" if host is None else host
Expand Down Expand Up @@ -200,7 +202,6 @@ class Configuration:
self.proxy = None
self.proxy_headers = None
self.safe_chars_for_path_param = ""
self.retries = None
# Enable client side validation
self.client_side_validation = True

Expand All @@ -217,6 +218,11 @@ class Configuration:
self.check_return_type = check_return_type
self.spec_property_naming = spec_property_naming

# Options for http retry
self.enable_retry = enable_retry
self.retry_backoff_factor = retry_backoff_factor
self.max_retries = max_retries

# Keep track of unstable operations
self.unstable_operations = _UnstableOperations({
{%- for version, api in apis.items() %}
Expand Down
41 changes: 38 additions & 3 deletions .generator/src/generator/templates/rest.j2
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import re
import ssl
from urllib.parse import urlencode
import zlib

import urllib3 # type: ignore

from {{ package }}.exceptions import (
Expand All @@ -21,6 +20,36 @@ from {{ package }}.exceptions import (

logger = logging.getLogger(__name__)

class DDRetry(urllib3.util.Retry):
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 500, 501, 502, 503, 504, 505, 506, 507, 509, 510, 511])
DEFAULT_ALLOWED_METHODS = frozenset(
["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE", "POST", "CONNECT", "PATCH"]
)
def __init__(self,**kwargs):
super().__init__(**kwargs)

def get_retry_after(self, response):

"""This method overrides the default "Retry-after" header and uses dd's X-Ratelimit-Reset header
and gets the value of X-Ratelimit-Reset in seconds."""

retry_after = response.headers.get("X-Ratelimit-Reset")

if retry_after is None:
return None
return self.parse_retry_after(retry_after)

def is_retry(self, method, status_code, has_retry_after=False):
if not self._is_method_retryable(method):
return False

if self.status_forcelist and status_code in self.status_forcelist:
return True
return (
self.total
and self.respect_retry_after_header
and (status_code in self.RETRY_AFTER_STATUS_CODES)
)

class RESTClientObject:
def __init__(self, configuration, pools_size=4, maxsize=4):
Expand All @@ -40,8 +69,14 @@ class RESTClientObject:
if configuration.assert_hostname is not None:
addition_pool_args["assert_hostname"] = configuration.assert_hostname

if configuration.retries is not None:
addition_pool_args["retries"] = configuration.retries
if configuration.enable_retry == True:
retries = DDRetry(
total=configuration.max_retries,
backoff_factor=configuration.retry_backoff_factor,
)
addition_pool_args["retries"] = retries
else:
addition_pool_args["retries"] = False

if configuration.socket_options is not None:
addition_pool_args["socket_options"] = configuration.socket_options
Expand Down
9 changes: 8 additions & 1 deletion src/datadog_api_client/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ def __init__(
check_input_type=True,
check_return_type=True,
spec_property_naming=False,
enable_retry=False,
retry_backoff_factor=2,
max_retries=3,
):
"""Constructor."""
self._base_path = "https://api.datadoghq.com" if host is None else host
Expand Down Expand Up @@ -201,7 +204,6 @@ def __init__(
self.proxy = None
self.proxy_headers = None
self.safe_chars_for_path_param = ""
self.retries = None
# Enable client side validation
self.client_side_validation = True

Expand All @@ -218,6 +220,11 @@ def __init__(
self.check_return_type = check_return_type
self.spec_property_naming = spec_property_naming

# Options for http retry
self.enable_retry = enable_retry
self.retry_backoff_factor = retry_backoff_factor
self.max_retries = max_retries

# Keep track of unstable operations
self.unstable_operations = _UnstableOperations(
{
Expand Down
39 changes: 36 additions & 3 deletions src/datadog_api_client/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import ssl
from urllib.parse import urlencode
import zlib

import urllib3 # type: ignore

from datadog_api_client.exceptions import (
Expand All @@ -24,6 +23,34 @@
logger = logging.getLogger(__name__)


class DDRetry(urllib3.util.Retry):
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 500, 501, 502, 503, 504, 505, 506, 507, 509, 510, 511])
DEFAULT_ALLOWED_METHODS = frozenset(
["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE", "POST", "CONNECT", "PATCH"]
)

def __init__(self, **kwargs):
super().__init__(**kwargs)

def get_retry_after(self, response):
"""This method overrides the default "Retry-after" header and uses dd's X-Ratelimit-Reset header
and gets the value of X-Ratelimit-Reset in seconds."""

retry_after = response.headers.get("X-Ratelimit-Reset")

if retry_after is None:
return None
return self.parse_retry_after(retry_after)

def is_retry(self, method, status_code, has_retry_after=False):
if not self._is_method_retryable(method):
return False

if self.status_forcelist and status_code in self.status_forcelist:
return True
return self.total and self.respect_retry_after_header and (status_code in self.RETRY_AFTER_STATUS_CODES)


class RESTClientObject:
def __init__(self, configuration, pools_size=4, maxsize=4):
# urllib3.PoolManager will pass all kw parameters to connectionpool
Expand All @@ -42,8 +69,14 @@ def __init__(self, configuration, pools_size=4, maxsize=4):
if configuration.assert_hostname is not None:
addition_pool_args["assert_hostname"] = configuration.assert_hostname

if configuration.retries is not None:
addition_pool_args["retries"] = configuration.retries
if configuration.enable_retry == True:
retries = DDRetry(
total=configuration.max_retries,
backoff_factor=configuration.retry_backoff_factor,
)
addition_pool_args["retries"] = retries
else:
addition_pool_args["retries"] = False

if configuration.socket_options is not None:
addition_pool_args["socket_options"] = configuration.socket_options
Expand Down
Loading