Closed meooow25 closed 5 years ago
Untested sketch of a rate limiter
import time
import itertools
def rate_limit(f, per_second, active = {}, counter = itertools.count()):
async def wrapped(*args, **kwargs):
req_id = next(counter)
now = time.time()
# Next valid slot is 1s after the `per_second`th last request
next_valid = now
if len(active) >= per_second:
next_valid = max(next_valid, active[list(active.keys())[-per_second]])
active[req_id] = next_valid
# Delay as needed
delay = next_valid - now
if delay > 0:
await asyncio.sleep(delay)
result = await f(*args, **kwargs)
del active[req_id]
return result
return wrapped
If it looks reasonable I can test it and make a PR.
Unlike blues who must be disrespected
Ok, revamped and seems to work fine.
from collections import deque
import asyncio
import time
def cf_ratelimit(f):
per_second = 5
last = deque([0]*per_second)
async def wrapped(*args, **kwargs):
now = time.time()
# Next valid slot is 1s after the `per_second`th last request
next_valid = max(now, 1 + last[0])
last.append(next_valid)
last.popleft()
# Delay as needed
delay = next_valid - now
if delay > 0:
await asyncio.sleep(delay)
return await f(*args, **kwargs)
return wrapped
@cf_ratelimit
async def f(s):
print(s)
async def main():
for i in range(50):
await f(i)
asyncio.run(main())
Looks good. We should also integrate the lock here, and implement API request retries if possible.
@algmyr can you create a pull request?
Closed by #82. Can be replaced later on if we want something more fancy.
Source documentation