Skip to content

Commit d6db7b7

Browse files
authored
Add support for multiple ratelimit headers (#311)
1 parent 566c016 commit d6db7b7

File tree

3 files changed

+37
-6
lines changed

3 files changed

+37
-6
lines changed

socketshark/config_defaults.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@
5252
'wait': 3,
5353
# If we encounter HTTP 429, wait for the amount of seconds specified in
5454
# the following header (fall back to the 'wait' value if it doesn't exist).
55-
'rate_limit_reset_header_name': 'X-Rate-Limit-Reset',
55+
'rate_limit_reset_header_name': 'X-Rate-Limit-Reset', # Deprecated, use rate_limit_reset_header_names instead.
56+
'rate_limit_reset_header_names': [], # List of header names to check for the rate limit reset time.
5657
}
5758

5859
# Redis options

socketshark/utils.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@ def _get_rate_limit_wait(log, resp, opts):
2121

2222
wait = opts['wait']
2323

24-
header_name = opts['rate_limit_reset_header_name']
25-
if header_name and header_name in resp.headers:
26-
header_value = resp.headers[header_name]
24+
header_names = opts['rate_limit_reset_header_names'] or [
25+
opts['rate_limit_reset_header_name']
26+
]
27+
header_value = None
28+
for header_name in header_names:
29+
if header_name in resp.headers:
30+
header_value = resp.headers[header_name]
31+
break
32+
if header_value:
2733
try:
2834
new_wait = float(header_value)
2935
# Make sure we have a valid value (not negative, NaN, or Inf)
@@ -48,6 +54,10 @@ def _get_rate_limit_wait(log, resp, opts):
4854
name=header_name,
4955
value=header_value,
5056
)
57+
else:
58+
log.warn(
59+
'got a 429 but no rate limit reset header found in response',
60+
)
5161
return wait
5262

5363

tests/test_basic.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,13 +1855,33 @@ def dummy_ping(*args, **kwargs):
18551855
await shark.shutdown()
18561856

18571857
@pytest.mark.asyncio
1858-
async def test_rate_limit(self):
1858+
@pytest.mark.parametrize(
1859+
'response_header_name, config_header_names, config_header_name',
1860+
(
1861+
(
1862+
'X-Rate-Limit-Reset',
1863+
['X-Rate-Limit-Reset', 'Retry-After'],
1864+
None,
1865+
),
1866+
('Retry-After', ['X-Rate-Limit-Reset', 'Retry-After'], None),
1867+
('X-Rate-Limit-Reset', [], 'X-Rate-Limit-Reset'),
1868+
),
1869+
)
1870+
async def test_rate_limit(
1871+
self, response_header_name, config_header_names, config_header_name
1872+
):
18591873
"""
18601874
Make sure SocketShark retries 429 responses appropriately.
18611875
"""
18621876
http_retry_config = TEST_CONFIG.copy()
18631877
http_retry_config['HTTP']['tries'] = 2
18641878
http_retry_config['HTTP']['wait'] = 1
1879+
http_retry_config['HTTP'][
1880+
'rate_limit_reset_header_names'
1881+
] = config_header_names
1882+
http_retry_config['HTTP'][
1883+
'rate_limit_reset_header_name'
1884+
] = config_header_name
18651885
shark = SocketShark(http_retry_config)
18661886
await shark.prepare()
18671887
client = MockClient(shark)
@@ -1876,7 +1896,7 @@ async def test_rate_limit(self):
18761896
conf['before_subscribe'],
18771897
status=429,
18781898
headers={
1879-
'X-Rate-Limit-Reset': '0.2',
1899+
response_header_name: '0.2',
18801900
},
18811901
)
18821902
mock.post(

0 commit comments

Comments
 (0)