Getting Started
Quickstart (Local)
Start with synchronous, in-process rate limiting and no Redis dependency.
Use local provider when one process owns limiter state.

Build provider
use trypema::{
BucketSize, RateLimit, RateLimitDecision, RateLimiterBuilder, WindowSize,
local::LocalRateLimiterProvider,
};
let provider = LocalRateLimiterProvider::builder()
.window_size(WindowSize::minutes_or_panic(1))
.bucket_size(BucketSize::milliseconds_or_panic(10))
.build()
.unwrap();
let rate = RateLimit::per_second_or_panic(5.0);
assert!(matches!(
provider.absolute().inc("user_123", &rate, 1),
RateLimitDecision::Allowed
));
build() returns an Arc and starts stale-state cleanup. Use .disable_cleanup() during
construction when cleanup is unwanted. After construction, start_cleanup_loop() and
stop_cleanup_loop() are idempotent.
Read live state
let absolute_total: u64 = provider.absolute().get("user_123");
let suppressed = provider.suppressed().get("user_123");
assert_eq!(absolute_total, 1);
assert_eq!(suppressed.total, 0);
assert_eq!(suppressed.total_declined, 0);
Unknown keys return zero-valued results without creating state. Reads include only live buckets
and may lazily evict expired history. is_allowed(...) checks absolute admission without
recording usage; get_suppression_factor(...) reads suppressed pressure.

