premier is an intuitive throttler that supports various backends and throttling algorihms, it can be used in distributed application for throttling web-api and any regular function.
- Distributed throttling via redis or other backend.
- Support asyncio mode
- Support various throttling algorithms
- Designed to be highly customizable and extensible.
- decorate functions to be throttled
from premier import limits, throttler, ThrottleAlgo
@throttler.fixed_window(quota=quota, duration_s=5, algo=ThrottleAlgo.FIXED_WINDOW)
def add(a: int, b: int) -> int:
res = a + b
return res
- config throttler when app starts
redis = Redis.from_url("redis://@127.0.0.1:6379/0")
throttler.config(
quota_counter=RedisCounter(redis=redis, ex_s=15), # set key expirey to 15 seconds
algo=ThrottleAlgo.FIXED_WINDOW,# use fix window as the default throttling algorithm
keyspace="premier", # set premier as the keyspace
)
pip install premier
by default, premier creates keyspace of this format for throttled functions
{keyspace}:{module}:{funcname}:{algorithm}
name | explain | default |
---|---|---|
keyspace | customized string provided by user | "premier" |
module | module name where function is defined in | func.__module__ |
funcname | name of the function | func.__name__ |
algorithm | throttling algorithm of the function | fixed_window |
You might provide your own keymaker to the 'throttler' function like this
from premier import throttler
@throttler.fixed_window(quota=3, duration_s=5, keymaker=lambda a, b: f"{a}")
def add(a: int, b: int) -> int:
res = a + b
return res
backend | sync | async |
---|---|---|
redis | supported | supported |
memory | supported | supported |
algorithm | status |
---|---|
fixed window | supported |
sliding window | supported |
leaky bucket | supported |
token bucket | supported |
- python >= 3.10
- redis >= 5.0.3
TODO:
-
support lowering version python by using type-extensions
-
implement timeout feature
-
implement retry feature
-
implement cache feature
API Design:
type Strategy = ty.Callable[[int], float]
@cache
@retry(strategy="expo", max=3, on_exception=(TimeOut, QuotaExceeds))
@timeout(60)
@throttler.leaky_bucket
def add(a:int, b:int):
return a + b