Skip to content

Instantly share code, notes, and snippets.

@jose-neta
Forked from pquentin/ratelimiter.py
Created March 16, 2024 16:53
Show Gist options
  • Save jose-neta/05a387a3090931e9d3c8dc133e523d9f to your computer and use it in GitHub Desktop.
Save jose-neta/05a387a3090931e9d3c8dc133e523d9f to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import asyncio
import time
import aiohttp
START = time.monotonic()
class RateLimiter:
"""Rate limits an HTTP client that would make get() and post() calls.
Calls are rate-limited by host.
https://quentin.pradet.me/blog/how-do-you-rate-limit-calls-with-aiohttp.html
This class is not thread-safe."""
RATE = 1 # one request per second
MAX_TOKENS = 10
def __init__(self, client):
self.client = client
self.tokens = self.MAX_TOKENS
self.updated_at = time.monotonic()
async def get(self, *args, **kwargs):
await self.wait_for_token()
now = time.monotonic() - START
print(f'{now:.0f}s: ask {args[0]}')
return self.client.get(*args, **kwargs)
async def wait_for_token(self):
while self.tokens < 1:
self.add_new_tokens()
await asyncio.sleep(0.1)
self.tokens -= 1
def add_new_tokens(self):
now = time.monotonic()
time_since_update = now - self.updated_at
new_tokens = time_since_update * self.RATE
if self.tokens + new_tokens >= 1:
self.tokens = min(self.tokens + new_tokens, self.MAX_TOKENS)
self.updated_at = now
async def fetch_one(client, i):
url = f'https://httpbin.org/get?i={i}'
# Watch out for the extra 'await' here!
async with await client.get(url) as resp:
resp = await resp.json()
now = time.monotonic() - START
print(f"{now:.0f}s: got {resp['args']}")
async def main():
async with aiohttp.ClientSession() as client:
client = RateLimiter(client)
tasks = [asyncio.ensure_future(fetch_one(client, i)) for i in range(20)]
await asyncio.gather(*tasks)
if __name__ == '__main__':
# Requires Python 3.7+
asyncio.run(main())
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment