Skip to content

Commit e24601c

Browse files
authored
Add retries for addtional response codes (#106)
* Add retries for status code 503, and status codes 502 and 504 on GET requests. For 503s, requests can be retried after between 2-4 seconds, for 502 and 504s, we want a retry every 60-90 seconds, with that number increasing each time we retry * Bump up version, even though 1.2 was never released * Address review comments * Adjust comment * single quotes
1 parent 139f1a7 commit e24601c

File tree

1 file changed

+35
-2
lines changed

1 file changed

+35
-2
lines changed

closeio_api/__init__.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import logging
22
import time
33

4+
from random import uniform
5+
46
import requests
57

68
from closeio_api.utils import local_tz_offset
@@ -9,7 +11,7 @@
911

1012
# To update the package version, change this variable. This variable is also
1113
# read by setup.py when installing the package.
12-
__version__ = '1.2'
14+
__version__ = '1.3'
1315

1416
class APIError(Exception):
1517
"""Raised when sending a request to the API failed."""
@@ -110,6 +112,21 @@ def _dispatch(self, method_name, endpoint, api_key=None, data=None,
110112
logging.debug('Request was rate limited, sleeping %d seconds', sleep_time)
111113
time.sleep(sleep_time)
112114
continue
115+
116+
# Retry 503 errors or 502 or 504 erors on GET requests.
117+
elif response.status_code == 503 or (
118+
method_name == 'get' and response.status_code in (502, 504)
119+
):
120+
sleep_time = self._get_randomized_sleep_time_for_error(
121+
response.status_code, retry_count
122+
)
123+
logging.debug(
124+
'Request hit a {}, sleeping for {} seconds'.format(
125+
response.status_code, sleep_time
126+
)
127+
)
128+
time.sleep(sleep_time)
129+
continue
113130

114131
# Break out of the retry loop if the request was successful.
115132
break
@@ -122,14 +139,30 @@ def _dispatch(self, method_name, endpoint, api_key=None, data=None,
122139
raise APIError(response)
123140

124141
def _get_rate_limit_sleep_time(self, response):
125-
"""Get rate limit window expiration time from response."""
142+
"""Get rate limit window expiration time from response if the response
143+
status code is 429.
144+
"""
126145
try:
127146
data = response.json()
128147
return float(data['error']['rate_reset'])
129148
except (AttributeError, KeyError, ValueError):
130149
logging.exception('Error parsing rate limiting response')
131150
return DEFAULT_RATE_LIMIT_DELAY
132151

152+
def _get_randomized_sleep_time_for_error(self, status_code, retries):
153+
"""Get sleep time for a given status code before we can try the
154+
request again.
155+
156+
Each time we retry, we want to increase the time before we try again.
157+
"""
158+
if status_code == 503:
159+
return uniform(2, 4) * (retries + 1)
160+
161+
elif status_code in (502, 504):
162+
return uniform(60, 90) * (retries + 1)
163+
164+
return DEFAULT_RATE_LIMIT_DELAY
165+
133166
def get(self, endpoint, params=None, timeout=None, **kwargs):
134167
"""Send a GET request to a given endpoint, for example:
135168

0 commit comments

Comments
 (0)