From 8e70e1fd4d22aecbc68cbe3e546e0b94324c329e Mon Sep 17 00:00:00 2001 From: Anthony Martinet Date: Fri, 9 Nov 2018 12:31:13 +0100 Subject: [PATCH 1/2] feat(backoff): implement backoff when ApiError is called ? --- ovh/client.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/ovh/client.py b/ovh/client.py index b8fff5c..3015e16 100644 --- a/ovh/client.py +++ b/ovh/client.py @@ -34,6 +34,7 @@ - To get started with API: https://api.ovh.com/g934.first_step_with_api """ +import backoff import hashlib import json import keyword @@ -122,6 +123,7 @@ def __init__( consumer_key=None, timeout=TIMEOUT, config_file=None, + auto_retry=None, ): """ Creates a new Client. No credential check is done at this point. @@ -150,6 +152,7 @@ def __init__( :param str consumer_key: uniquely identifies :param tuple timeout: Connection and read timeout for each request :param float timeout: Same timeout for both connection and read + :param init auto_retry: Number of times backoff will retry if a call fail :raises InvalidRegion: if ``endpoint`` can't be found in ``ENDPOINTS``. """ # Load a custom config file if requested @@ -187,8 +190,18 @@ def __init__( # Override default timeout self._timeout = timeout + # Set default auto_retry + self._auto_retry = auto_retry + # high level API + def retry_call(self, *args, **kwargs): + if self._auto_retry is None: + return self.call(*args, **kwargs) + else: + return backoff.on_exception(backoff.expo, APIError, max_tries=self._auto_retry)(self.call)(*args, **kwargs) + + @property def time_delta(self): """ @@ -352,7 +365,7 @@ def get(self, _target, _need_auth=True, **kwargs): else: _target = "%s?%s" % (_target, query_string) - return self.call("GET", _target, None, _need_auth) + return self.retry_call('GET', _target, None, _need_auth) def put(self, _target, _need_auth=True, **kwargs): """ @@ -369,7 +382,7 @@ def put(self, _target, _need_auth=True, **kwargs): kwargs = self._canonicalize_kwargs(kwargs) if not kwargs: kwargs = None - return self.call("PUT", _target, kwargs, _need_auth) + return self.retry_call('PUT', _target, kwargs, _need_auth) def post(self, _target, _need_auth=True, **kwargs): """ @@ -386,7 +399,7 @@ def post(self, _target, _need_auth=True, **kwargs): kwargs = self._canonicalize_kwargs(kwargs) if not kwargs: kwargs = None - return self.call("POST", _target, kwargs, _need_auth) + return self.retry_call('POST', _target, kwargs, _need_auth) def delete(self, _target, _need_auth=True, **kwargs): """ @@ -409,10 +422,11 @@ def delete(self, _target, _need_auth=True, **kwargs): else: _target = "%s?%s" % (_target, query_string) - return self.call("DELETE", _target, None, _need_auth) + return self.retry_call('DELETE', _target, None, _need_auth) # low level helpers + def call(self, method, path, data=None, need_auth=True): """ Low level call helper. If ``consumer_key`` is not ``None``, inject From afba24fcb2a8bbefcc68d8fa5b582d298fb87f55 Mon Sep 17 00:00:00 2001 From: Anthony Martinet Date: Wed, 29 Mar 2023 14:18:24 +0200 Subject: [PATCH 2/2] feat(auto_retry): added exception on which to perform auto_retry as parameters --- ovh/client.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/ovh/client.py b/ovh/client.py index 3015e16..62913b1 100644 --- a/ovh/client.py +++ b/ovh/client.py @@ -124,6 +124,7 @@ def __init__( timeout=TIMEOUT, config_file=None, auto_retry=None, + auto_retry_on_exceptions=None, ): """ Creates a new Client. No credential check is done at this point. @@ -152,7 +153,8 @@ def __init__( :param str consumer_key: uniquely identifies :param tuple timeout: Connection and read timeout for each request :param float timeout: Same timeout for both connection and read - :param init auto_retry: Number of times backoff will retry if a call fail + :param int auto_retry: Number of times backoff will retry if a call fail + :param tuple auto_retry_on_exceptions: Exceptions that need to perform an auto_retry :raises InvalidRegion: if ``endpoint`` can't be found in ``ENDPOINTS``. """ # Load a custom config file if requested @@ -193,14 +195,21 @@ def __init__( # Set default auto_retry self._auto_retry = auto_retry - # high level API + # Set default auto_retry_on_exceptions + if self.auto_retry_on_exceptions is None: + self._auto_retry_on_exceptions = (HTTPError, NetworkError) + else: + self._auto_retry_on_exceptions = auto_retry_on_exceptions + # high level API def retry_call(self, *args, **kwargs): + """Perform raw query and handle auto_retry if necessary.""" if self._auto_retry is None: return self.call(*args, **kwargs) else: - return backoff.on_exception(backoff.expo, APIError, max_tries=self._auto_retry)(self.call)(*args, **kwargs) - + return backoff.on_exception(backoff.expo, + self._auto_retry_on_exceptions, + max_tries=self._auto_retry)(self.call)(*args, **kwargs) @property def time_delta(self): @@ -426,7 +435,6 @@ def delete(self, _target, _need_auth=True, **kwargs): # low level helpers - def call(self, method, path, data=None, need_auth=True): """ Low level call helper. If ``consumer_key`` is not ``None``, inject