Skip to content
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

Max Rate Limit Retry #123

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 13 additions & 1 deletion dnacentersdk/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
DEFAULT_BASE_URL,
DEFAULT_SINGLE_REQUEST_TIMEOUT,
DEFAULT_WAIT_ON_RATE_LIMIT,
DEFAULT_MAX_RETRIES_ON_RATE_LIMIT,
DEFAULT_VERIFY,
)
import dnacentersdk.environment as dnacenter_environment
Expand Down Expand Up @@ -654,6 +655,7 @@ def __init__(self, username=None,
base_url=None,
single_request_timeout=None,
wait_on_rate_limit=None,
max_retries_on_rate_limit=None,
verify=None,
version=None,
debug=None,
Expand Down Expand Up @@ -700,6 +702,11 @@ def __init__(self, username=None,
environment variable or
dnacentersdk.config.DEFAULT_WAIT_ON_RATE_LIMIT
if the environment variable is not set.
max_retries_on_rate_limit(int): Maximum number of request retries
performed by automatic rate-limit handling Defaults to the
DNA_CENTER_MAX_RETRIES_ON_RATE_LIMIT environment variable or
dnacentersdk.config.DEFAULT_MAX_RETRIES_ON_RATE_LIMIT
if the environment variable is not set.
verify(bool,basestring): Controls whether we verify the server's
TLS certificate, or a string, in which case it must be a path
to a CA bundle to use. Defaults to the DNA_CENTER_VERIFY
Expand Down Expand Up @@ -745,8 +752,12 @@ def __init__(self, username=None,
if wait_on_rate_limit is None:
wait_on_rate_limit = dnacenter_environment.get_env_wait_on_rate_limit() or DEFAULT_WAIT_ON_RATE_LIMIT

if max_retries_on_rate_limit is None:
max_retries_on_rate_limit = dnacenter_environment.get_env_max_retries_on_rate_limit() \
if dnacenter_environment.get_env_max_retries_on_rate_limit() is not None else DEFAULT_MAX_RETRIES_ON_RATE_LIMIT

if verify is None:
verify = dnacenter_environment.get_env_verify() if dnacenter_environment.get_env_verify() != None else DEFAULT_VERIFY
verify = dnacenter_environment.get_env_verify() if dnacenter_environment.get_env_verify() is not None else DEFAULT_VERIFY

version = version or dnacenter_environment.get_env_version() or DEFAULT_VERSION

Expand Down Expand Up @@ -813,6 +824,7 @@ def get_access_token():
base_url=base_url,
single_request_timeout=single_request_timeout,
wait_on_rate_limit=wait_on_rate_limit,
max_retries_on_rate_limit=max_retries_on_rate_limit,
verify=verify,
version=version,
debug=debug,
Expand Down
4 changes: 4 additions & 0 deletions dnacentersdk/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@
#: Enables or disables automatic rate-limit handling.
DEFAULT_WAIT_ON_RATE_LIMIT = True

#: **retries_on_rate_limit** default value.
#: Maximum number of times automatic rate-limit handling retries requests.
DEFAULT_MAX_RETRIES_ON_RATE_LIMIT = 5

#: **verify** default value.
#: Controls whether to verify the server's TLS certificate or not.
DEFAULT_VERIFY = True
10 changes: 10 additions & 0 deletions dnacentersdk/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
#: name of the environment wait_on_rate_limit variable
WAIT_ON_RATE_LIMIT_ENVIRONMENT_VARIABLE = 'DNA_CENTER_WAIT_ON_RATE_LIMIT'

#: name of the environment max_retries_on_rate_limit variable
MAX_RETRIES_ON_RATE_LIMIT_ENVIRONMENT_VARIABLE = 'DNA_CENTER_MAX_RETRIES_ON_RATE_LIMIT'

#: name of the environment verify variable
VERIFY_ENVIRONMENT_VARIABLE = 'DNA_CENTER_VERIFY'

Expand Down Expand Up @@ -120,6 +123,13 @@ def get_env_wait_on_rate_limit():
return DNA_CENTER_WAIT_ON_RATE_LIMIT


def get_env_max_retries_on_rate_limit():
DNA_CENTER_MAX_RETRIES_ON_RATE_LIMIT = _get_env_value(
MAX_RETRIES_ON_RATE_LIMIT_ENVIRONMENT_VARIABLE,
int, int)
return DNA_CENTER_MAX_RETRIES_ON_RATE_LIMIT


def get_env_verify():
DNA_CENTER_VERIFY = _get_env_value(VERIFY_ENVIRONMENT_VARIABLE, bool, _is_bool)
return DNA_CENTER_VERIFY
23 changes: 9 additions & 14 deletions dnacentersdk/restsession.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
DEFAULT_SINGLE_REQUEST_TIMEOUT,
DEFAULT_VERIFY,
DEFAULT_WAIT_ON_RATE_LIMIT,
DEFAULT_MAX_RETRIES_ON_RATE_LIMIT,
)
from .exceptions import (
ApiError,
Expand Down Expand Up @@ -140,6 +141,7 @@ class RestSession(object):
def __init__(self, get_access_token, access_token, base_url,
single_request_timeout=DEFAULT_SINGLE_REQUEST_TIMEOUT,
wait_on_rate_limit=DEFAULT_WAIT_ON_RATE_LIMIT,
max_retries_on_rate_limit=DEFAULT_MAX_RETRIES_ON_RATE_LIMIT,
verify=DEFAULT_VERIFY,
version=None,
debug=False):
Expand All @@ -156,6 +158,8 @@ def __init__(self, get_access_token, access_token, base_url,
HTTP REST API request.
wait_on_rate_limit(bool): Enable or disable automatic rate-limit
handling.
max_retries_on_rate_limit(int): Maximum number of request retries
performed by automatic rate-limit handling
verify(bool,basestring): Controls whether we verify the server's
TLS certificate, or a string, in which case it must be a path
to a CA bundle to use.
Expand Down Expand Up @@ -186,6 +190,7 @@ def __init__(self, get_access_token, access_token, base_url,
self._access_token = str(access_token)
self._single_request_timeout = single_request_timeout
self._wait_on_rate_limit = wait_on_rate_limit
self._max_retries_on_rate_limit = max_retries_on_rate_limit
self._verify = verify
self._version = version
self._debug = debug
Expand Down Expand Up @@ -436,6 +441,7 @@ def request(self, method, url, erc, custom_refresh, **kwargs):
kwargs.pop('data', None)

c = custom_refresh
rate_limit_retry = 0
while True:
c += 1
# Make the HTTP request to the API endpoint
Expand All @@ -454,26 +460,15 @@ def request(self, method, url, erc, custom_refresh, **kwargs):
**kwargs)
except Exception as e:
raise dnacentersdkException('Socket error {}'.format(e))
except IOError as e:
if e.errno == errno.EPIPE:
# EPIPE error
try:
c += 1
logger.debug('Attempt {}'.format(c))
response = self._req_session.request(method, abs_url,
**kwargs)
except Exception as e:
raise dnacentersdkException('PipeError {}'.format(e))
else:
raise dnacentersdkException('IOError {}'.format(e))
try:
# Check the response code for error conditions
check_response_code(response, erc)
except RateLimitError as e:
# Catch rate-limit errors
# Wait and retry if automatic rate-limit handling is enabled
if self.wait_on_rate_limit:
warnings.warn(RateLimitWarning(response))
if self.wait_on_rate_limit and rate_limit_retry < self._max_retries_on_rate_limit:
logger.warning(RateLimitWarning(response))
rate_limit_retry += 1
time.sleep(e.retry_after)
continue
else:
Expand Down