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 LimitedError.
from throttled import Throttled, exceptions
quota = "2/m"
# 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() -> None:
# The first call will not be rate limited.
# >> pong
print(ping()) # type: ignore[call-arg]
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() # type: ignore[call-arg]
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
quota = "2/m"
# 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() -> None:
# 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())