Skip to main content

Crate rate_net

Crate rate_net 

Source
Expand description

§rate-net

A powerful, lock-free rate limiter for Rust. It answers one question as fast as the hardware allows — “is this key allowed right now?” — and answers it with a Decision (allow / deny plus a retry-after), across multiple algorithms, while tracking per-key state under high contention. Per-key state lives in a sharded concurrent map, so unrelated keys never contend and throughput scales with core count; each key’s bucket is lock-free and memory is bounded by eviction, so a flood of unique keys hits a cap instead of growing without limit.

rate-net does not reimplement token-bucket accounting. It consumes better-bucket for that and reads time from clock-lib, then adds the per-key, multi-algorithm, retry-after machinery around them. It is the anchor crate of the -net domain group and is consumed by gatekeepers (such as bouncer-io) through the clean decision API — they call check and never reach into its internal state.

§Status

Pre-1.0 beta (0.9.0): the API is frozen (since 0.7.0) and locked in at the type level too — every public type is Send + Sync + 'static and that is asserted at compile time. The integration shake-out at 0.8.0 confirmed the surface is consumable through the public allow/deny API only, and 0.9.0 widens the concurrency coverage: a single hot key under eight threads against every algorithm admits exactly its quota — never more (no over-admit, no torn updates) and never fewer (no lost decrements, no deadlock). The five algorithms sit behind the one Limiter trait (token bucket by default; the leaky bucket and window algorithms under the algorithms feature), with the Tier-2 Builder, an optional AsyncLimiter await-until-ready layer (async feature), runnable examples, and a criterion suite. Per-key state lives in a purpose-built sharded store (an existing-key check takes only a shard read lock plus the algorithm’s atomic accounting, so unrelated keys never contend), memory is bounded by eviction, and the steady-state check is allocation-free. From here, the only changes before 1.0 are bug fixes and documentation polish.

use rate_net::{RateLimiter, Decision};

// 100 requests per second, per key.
let limiter = RateLimiter::per_second(100);

match limiter.check("user:42") {
    Decision::Allow => {
        // allowed — serve the request
    }
    Decision::Deny { retry_after } => {
        // denied — return 429 with `Retry-After: retry_after`
        let _ = retry_after;
    }
    _ => {}
}

§Design goals

  • Lock-free per key. Each key’s bucket delegates to better-bucket’s atomic compare-and-swap core; no lock sits on the check path.
  • Sharded state. Per-key state lives in a sharded concurrent map, so unrelated keys land in different shards and never serialize on each other. Throughput scales with cores; shard count is tunable.
  • Zero-allocation steady state. A check on an existing key allocates nothing; allocation happens only the first time a key is seen.
  • Bounded memory. Idle keys are evicted (LRU/TTL) on an amortized, incremental schedule that never stops the world on the hot path. A hostile unique-key flood reaches the eviction cap and stays there.
  • Never over-admits. For any key and window, admitted requests never exceed the configured quota under any concurrent interleaving — proven per algorithm with loom and proptest.
  • Lazy, runtime-free. Refill and expiry are computed from a monotonic clock on access; there is no background timer thread and the core has no async-runtime dependency.

§Feature flags

FeatureDefaultDescription
stdyesStandard library. Required for the sharded per-key store and eviction. With it off the crate is no_std; the scaffold then exposes only VERSION, and the pared-down single-key mode follows in a later release.
algorithmsnoThe full algorithm suite beyond the default token bucket: leaky bucket, fixed window, sliding-window log, sliding-window counter.
asyncnoOptional async-friendly wrapper layer. Additive only — the core has no runtime dependency.

Structs§

AsyncLimiter
An async-friendly wrapper around a RateLimiter.
Builder
A fluent builder for a RateLimiter when the Tier-1 constructors are not enough.
Eviction
How the limiter bounds the memory its per-key state can occupy.
Key
An opaque identity a rate limit is tracked against.
Quota
A rate limit: limit requests per period, per key, with a burst ceiling.
RateLimiter
A keyed rate limiter.

Enums§

Algorithm
Selects the algorithm a limiter uses to decide a request.
Decision
The result of checking a key against its limit.
RateLimiterError
A limit configuration rejected at construction time.

Constants§

DEFAULT_MAX_KEYS
The default key-capacity cap, applied unless overridden.
VERSION
The version of this crate, taken from Cargo.toml at compile time.

Traits§

Limiter
The shared rate-limiting surface, independent of the algorithm behind it.