Skip to content

Commit fa795b8

Browse files
author
rupa
authored
Add some logging to rate limit funcs and doc them some more. (#59)
1 parent d4a42f0 commit fa795b8

1 file changed

Lines changed: 40 additions & 6 deletions

File tree

ns1/rest/rate_limiting.py

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,64 @@
1+
"""
2+
NS1 rate limits via a "token bucket" scheme, and provides information about
3+
rate limiting in headers on the response. Token bucket can be thought of as an
4+
initially "full" bucket, where, if not full, tokens are replenished at some
5+
rate. This allows "bursting" requests until the bucket is empty, after which,
6+
you are limited to the rate of token replenishment.
7+
8+
Here we define a few "strategies" that may be helpful in avoiding 429 responses
9+
from the API.
10+
11+
Unfortunately, rate limiting is seperately "bucketed" per endpoint and method,
12+
and are not necessarily the same for all users. So the only way to know the
13+
status of a "bucket" is to make a request, and, for now, the strategies involve
14+
sleeping for some interval *after* we make requests. They are also not
15+
currently "bucket-aware".
16+
"""
17+
18+
import logging
19+
120
from time import sleep
221

22+
LOG = logging.getLogger(__name__)
23+
324

425
def rate_limit_strategy_solo():
526
"""
6-
sleep longer the closer we are to running out of tokens, but be blissfully
27+
Sleep longer the closer we are to running out of tokens, but be blissfully
728
unaware of anything else using up tokens.
829
"""
930

1031
def solo_rate_limit_func(rl):
1132
if rl["remaining"] < 2:
12-
sleep(rl["period"])
33+
wait = rl["period"]
1334
else:
14-
sleep(rl["period"] / rl["remaining"])
35+
wait = rl["period"] / rl["remaining"]
36+
LOG.debug("rate_limit_strategy_solo: sleeping for: {}s".format(wait))
37+
sleep(wait)
1538

1639
return solo_rate_limit_func
1740

1841

1942
def rate_limit_strategy_concurrent(parallelism):
2043
"""
21-
when we have equal or fewer tokens than workers, multiply our sleep
22-
interval by the number of workers.
44+
When we have equal or fewer tokens than workers, sleep for
45+
the token replenishment interval multiplied by the number of workers.
46+
47+
For example, if we can make 10 requests in 60 seconds, a token is
48+
replenished every 6 seconds. If parallelism is 3, we will burst 7 requests,
49+
and subsequently each process will sleep for 18 seconds before making
50+
another request.
2351
"""
2452

2553
def concurrent_rate_limit_func(rl):
2654
if rl["remaining"] <= parallelism:
27-
sleep((rl["period"] / rl["limit"]) * parallelism)
55+
wait = (rl["period"] / rl["limit"]) * parallelism
56+
LOG.debug(
57+
"rate_limit_strategy_concurrent={}: sleeping for: {}s".format(
58+
parallelism, wait
59+
)
60+
)
61+
sleep(wait)
2862

2963
return concurrent_rate_limit_func
3064

0 commit comments

Comments
 (0)