Sign in

    moonbitstack/moonzero/limit does not have a README file

    MaxConns

    pub struct MaxConns {
    max : Int
    in_flight : Int
    }

    A permit pool of max concurrent slots (← go-zero's syncx.Limit).

    MaxConns::in_flight

    fn MaxConns::in_flight(self : MaxConns) -> Int

    The number of requests currently holding a permit.

    MaxConns::new

    fn MaxConns::new(max : Int) -> MaxConns

    A pool admitting at most max requests at once.

    MaxConns::release

    fn MaxConns::release(self : MaxConns) -> Unit

    Return a permit taken by try_acquire (Return).

    MaxConns::try_acquire

    fn MaxConns::try_acquire(self : MaxConns) -> Bool

    Take a permit if one is free (TryBorrow), returning whether it was taken.

    PeriodLimit

    pub struct PeriodLimit {
    period_ms : Int64
    quota : Int
    windows : Map[String, (Int64, Int)]
    }

    A fixed-window rate limiter kept in this process: each key may make up to quota requests per period; a key's window opens on its first request and resets once period has elapsed. It is the counting complement of the continuous TokenBucket, and because every decision is a function of (state, now) it is exactly testable without a real clock.

    The window is local, so N replicas admit N quotas. RedisPeriodLimit is the same limiter with its window in redis and is what a fleet should run; this one is for a single process, and for the fallback a caller wants when redis is unreachable.

    PeriodLimit::new

    fn PeriodLimit::new(period_secs~ : Int, quota~ : Int) -> PeriodLimit

    A limiter admitting quota requests per period_secs seconds, per key.

    PeriodLimit::take

    fn PeriodLimit::take(self : PeriodLimit, key : String, now : Int64) -> PeriodResult

    Account for one request under key at now and report its outcome. Opens a fresh window if the key's current one has elapsed; PeriodAllowed below quota, PeriodHitQuota at exactly the quota (the last admitted request), and PeriodOverQuota beyond it.

    PeriodResult

    pub(all) enum PeriodResult {
    PeriodAllowed
    PeriodHitQuota
    PeriodOverQuota
    } derive(Eq,
    Debug
    )

    The outcome of a PeriodLimit.take (← go-zero's period-limit result codes): a request within quota, the one that reaches it exactly (still admitted), or one beyond it (rejected).

    PeriodResult::equal

    PeriodResult::not_equal

    fn PeriodResult::not_equal(x : PeriodResult, y : PeriodResult) -> Bool

    RedisPeriodLimit

    pub struct RedisPeriodLimit {
    client :
    RedisClient

    script :
    RedisScript

    period_secs : Int
    quota : Int
    prefix : String
    }

    A fixed-window rate limiter whose window lives in redis (← go-zero's limit.PeriodLimit). One INCRBY-ed counter per key, given a period-second expiry the first time it appears, so every replica pointed at the same redis and key draws on one quota instead of each getting its own.

    RedisPeriodLimit::new

    fn RedisPeriodLimit::new(client :
    RedisClient
    , period_secs~ : Int, quota~ : Int, prefix? : String) -> RedisPeriodLimit

    A limiter admitting quota requests per period_secs seconds per key, counting in client's redis under prefix-prefixed keys.

    RedisPeriodLimit::take

    Account for one request under key and report its outcome, in the same three states the local limiter reports. A code the script cannot have returned, or a reply that is not an integer at all, raises — go-zero answers Unknown with ErrUnknownCode there, and a caller has to decide what an undecided limiter means.

    RedisTokenLimit

    pub struct RedisTokenLimit {
    client :
    RedisClient

    script :
    RedisScript

    rate : Int
    burst : Int
    token_key : Bytes
    ts_key : Bytes
    rescue : TokenBucket
    }

    A token-bucket rate limiter whose bucket lives in redis (← go-zero's limit.TokenLimiter). The token count and the second it was last refilled sit under {key}.tokens and {key}.ts, so every replica pointed at the same redis and key spends from one bucket. When redis cannot be reached the limiter keeps limiting from rescue, its process-local TokenBucket, the way go-zero drops to its in-process rescueLimiter rather than letting an outage open the gate.

    RedisTokenLimit::allow

    async fn RedisTokenLimit::allow(self : RedisTokenLimit, now_ms : Int64) -> Bool

    Try to admit one request at now_ms.

    RedisTokenLimit::allow_n

    async fn RedisTokenLimit::allow_n(self : RedisTokenLimit, n : Int, now_ms : Int64) -> Bool

    Try to admit a request costing n tokens at now_ms. The script is handed whole seconds because go-zero hands it now.Unix(): the shared bucket refills at one-second granularity however finely the clock is read. Lua's false arrives as a null reply and its true as 1; anything else, and any redis failure, is served by the local bucket instead.

    RedisTokenLimit::new

    fn RedisTokenLimit::new(client :
    RedisClient
    , rate~ : Int, burst~ : Int, key~ : String) -> RedisTokenLimit

    A limiter admitting rate requests per second with room for a burst of that many back-to-back, over the bucket key names in client's redis.

    RedisTokenLimit::rescue

    The process-local bucket this limiter falls back to, so a caller can inspect it.

    TokenBucket

    pub struct TokenBucket {
    bucket :
    Bucket

    }

    A token-bucket rate limiter kept in this process: the bucket holds up to capacity tokens and refills continuously at refill_per_ms tokens per millisecond, and each admitted request spends one. Because every decision is a function of (state, now), the limiter is exactly testable without a real clock.

    The bucket is local, so N replicas admit N times the rate. RedisTokenLimit is the same limiter with its bucket in redis and is what a fleet should run; this one serves a single process, and is what RedisTokenLimit itself falls back to when redis is unreachable (← go-zero's rescueLimiter).

    TokenBucket::allow

    fn TokenBucket::allow(self : TokenBucket, now : Int64) -> Bool

    Try to admit one request at time now. Returns true when admitted, false when the bucket is empty.

    TokenBucket::allow_n

    fn TokenBucket::allow_n(self : TokenBucket, n : Double, now : Int64) -> Bool

    Try to admit a request costing n tokens at time now. Returns false (spending nothing) when fewer than n tokens are available.

    TokenBucket::available

    fn TokenBucket::available(self : TokenBucket, now : Int64) -> Double

    The (fractional) number of tokens currently available at now. Useful for metrics and tests.

    TokenBucket::new

    fn TokenBucket::new(rate : Double, burst? : Double, now? : Int64) -> TokenBucket

    Build a bucket admitting rate requests per second on average with room for a burst of that many back-to-back (default burst = rate). It starts full at time now, in milliseconds.

    The bucket is moonpool's; this keeps go-zero's shape and its millisecond clock. A capacity below one token is raised to one, because a bucket that can never hold a whole token admits nothing at all — which is what a fractional rate with no burst used to give.

    period_script

    let period_script : String

    go-zero's core/limit/periodscript.lua, verbatim: INCRBY the key, hang the window on it the first time it appears, and answer 1 below quota, 2 exactly at it, 0 past it. Public so a caller can pre-load it, and so a redis double can evaluate the very text the limiter ships.

    token_script

    let token_script : String

    go-zero's core/limit/tokenscript.lua, verbatim: read the bucket and the second it was last touched, refill by the elapsed seconds capped at capacity, spend requested if that many are there, and write both back under a TTL of two fill times. Public so a caller can pre-load it, and so a redis double can evaluate the very text the limiter ships.