Decorator#
You can use Throttled as a decorator, and the limit method will check if the request is allowed
before the wrapped function call.
If the request is not allowed, it will raise a LimitedError.
from throttled import Throttled, exceptions, rate_limiter
quota = rate_limiter.per_min(2)
# Create a rate limiter that allows 2 request per minute.
@Throttled(key="/ping", quota=quota)
def ping() -> str:
return "pong"
# Create a rate limiter that allows 2 cost per minute, consuming 2 Tokens per call.
@Throttled(key="/ping", quota=quota, cost=2)
def heavy_ping() -> str:
return "heavy_pong"
def main():
# The first call will not be rate limited.
# >> pong
print(ping())
try:
# The second call will be rate limited, because heavy_ping consumes 2 Tokens
# and 1 Token has been consumed by the first call.
heavy_ping()
except exceptions.LimitedError as exc:
# >> Rate limit exceeded: remaining=1, reset_after=30, retry_after=60.
print(exc)
if __name__ == "__main__":
main()
import asyncio
from throttled.asyncio import Throttled, exceptions, rate_limiter
quota = rate_limiter.per_min(2)
# Create a rate limiter that allows 2 request per minute.
@Throttled(key="/ping", quota=quota)
async def ping() -> str:
return "ping"
# Create a rate limiter that allows 2 cost per minute, consuming 2 Tokens per call.
@Throttled(key="/ping", quota=quota, cost=2)
async def heavy_ping() -> str:
return "heavy_pong"
async def main():
# The first call should succeed.
# >> pong
print(await ping())
try:
# The second call will be rate limited, because heavy_ping consumes 2 Tokens
# and 1 Token has been consumed by the first call.
await heavy_ping()
except exceptions.LimitedError as exc:
# >> Rate limit exceeded: remaining=1, reset_after=30, retry_after=60.
print(exc)
if __name__ == "__main__":
asyncio.run(main())