Getting Started

Quickstart (Hybrid)

Combine local admission with periodic Redis synchronization.

Use hybrid provider when distributed visibility matters but per-request Redis I/O is too costly.

Three paper-craft rate-limiter topologies showing local state, direct shared Redis state, and local state synchronized to Redis.
Local keeps state in one process; Redis centralizes every call; hybrid periodically synchronizes local state to Redis.

Add dependencies

[dependencies]
trypema = { version = "2", features = ["redis-tokio"] }
redis = { version = "1", features = ["aio", "tokio-comp", "connection-manager"] }
tokio = { version = "1", features = ["full"] }

Build provider

use trypema::{BucketSize, RateLimit, RateLimitDecision, RateLimiterBuilder, WindowSize};
use trypema::hybrid::{HybridRateLimiterProvider, SyncInterval};
use trypema::redis::RedisKey;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let connection = redis::Client::open("redis://127.0.0.1:6379/")?
        .get_connection_manager()
        .await?;
    let provider = HybridRateLimiterProvider::builder(connection)
        .prefix(RedisKey::try_from("my-service")?)
        .window_size(WindowSize::minutes_or_panic(1))
        .bucket_size(BucketSize::milliseconds_or_panic(10))
        .sync_interval(SyncInterval::milliseconds_or_panic(10))
        .build()?;

    let key = RedisKey::try_from("user_123")?;
    let rate = RateLimit::per_second_or_panic(10.0);
    assert!(matches!(
        provider.absolute().inc(&key, &rate, 1).await?,
        RateLimitDecision::Allowed
    ));

    Ok(())
}

Most admission calls use local state; background synchronization is always active. Smaller SyncInterval values reduce lag and increase Redis work. get(...) synchronizes with Redis and overlays this instance's pending counts; get_estimate(...) may answer from initialized local state.

Redis 7.2+ and exactly one runtime feature are required, just as for the Redis provider.

Next steps