Skip to content

Commit 8dd7fa3

Browse files
Fix rate limiting backoff behavior (#113)
1 parent 256b416 commit 8dd7fa3

File tree

5 files changed

+35
-34
lines changed

5 files changed

+35
-34
lines changed

.circleci/config.yml

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,36 @@ workflows:
44
version: 2
55
workflow:
66
jobs:
7-
- test-2.7
8-
- test-3.5
9-
- test-3.6
7+
- test-3.7
8+
- test-3.8
9+
- test-3.9
10+
- test-3.10
1011

1112
defaults: &defaults
1213
working_directory: ~/code
1314
steps:
1415
- checkout
1516
- run:
1617
name: Install dependencies
17-
command: sudo pip install -r requirements.txt
18+
command: pip install -r requirements.txt
1819
- run:
1920
name: Test
2021
command: pytest
2122

2223
jobs:
23-
test-2.7:
24+
test-3.7:
2425
<<: *defaults
2526
docker:
26-
- image: circleci/python:2.7
27-
test-3.5:
27+
- image: cimg/python:3.7
28+
test-3.8:
2829
<<: *defaults
2930
docker:
30-
- image: circleci/python:3.5
31-
test-3.6:
31+
- image: cimg/python:3.8
32+
test-3.9:
3233
<<: *defaults
3334
docker:
34-
- image: circleci/python:3.6
35+
- image: cimg/python:3.9
36+
test-3.10:
37+
<<: *defaults
38+
docker:
39+
- image: cimg/python:3.10

closeio_api/__init__.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import contextlib
12
import logging
23
import time
34

@@ -10,8 +11,8 @@
1011
DEFAULT_RATE_LIMIT_DELAY = 2 # Seconds
1112

1213
# To update the package version, change this variable. This variable is also
13-
# read by setup.py when installing the package.
14-
__version__ = '1.4'
14+
# read by setup.py when installing the package.
15+
__version__ = '2.0'
1516

1617
class APIError(Exception):
1718
"""Raised when sending a request to the API failed."""
@@ -145,12 +146,13 @@ def _get_rate_limit_sleep_time(self, response):
145146
"""Get rate limit window expiration time from response if the response
146147
status code is 429.
147148
"""
148-
try:
149-
data = response.json()
150-
return float(data['error']['rate_reset'])
151-
except (AttributeError, KeyError, ValueError):
152-
logging.exception('Error parsing rate limiting response')
153-
return DEFAULT_RATE_LIMIT_DELAY
149+
with contextlib.suppress(KeyError):
150+
return float(response.headers["Retry-After"])
151+
with contextlib.suppress(KeyError):
152+
return float(response.headers["RateLimit-Reset"])
153+
154+
logging.exception('Error parsing rate limiting response')
155+
return DEFAULT_RATE_LIMIT_DELAY
154156

155157
def _get_randomized_sleep_time_for_error(self, status_code, retries):
156158
"""Get sleep time for a given status code before we can try the

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
pytest==3.0.7
2-
requests==2.21.0
3-
responses==0.5.1
1+
pytest==7.1.1
2+
requests==2.27.1
3+
responses==0.20.0

setup.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
],
2020
classifiers=[
2121
"Programming Language :: Python",
22-
"Programming Language :: Python :: 2",
23-
"Programming Language :: Python :: 2.7",
2422
"Programming Language :: Python :: 3",
25-
"Programming Language :: Python :: 3.5",
26-
"Programming Language :: Python :: 3.6",
23+
"Programming Language :: Python :: 3.7",
24+
"Programming Language :: Python :: 3.8",
25+
"Programming Language :: Python :: 3.9",
26+
"Programming Language :: Python :: 3.10",
2727
"Operating System :: OS Independent",
2828
]
2929
)

tests/test_api.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,16 +114,10 @@ def test_retry_on_rate_limit(api_client):
114114
rsps.add(
115115
responses.GET,
116116
'https://api.close.com/api/v1/lead/lead_abcdefghijklmnop/',
117-
body=json.dumps({
118-
"error": {
119-
"rate_reset": 1,
120-
"message": "API call count exceeded for this 15 second window",
121-
"rate_limit": 600,
122-
"rate_window": 15
123-
}
124-
}),
117+
body=json.dumps({}),
125118
status=429,
126-
content_type='application/json'
119+
content_type='application/json',
120+
headers={"Retry-After": "1", "RateLimit-Reset": "1"}
127121
)
128122

129123
# Respond correctly to the second request.

0 commit comments

Comments
 (0)