Expand description
§Trypema
Trypema provides concurrent sliding-window rate limiters with absolute and probabilistic suppression strategies. Providers are constructed independently, so applications only create the local, Redis, or hybrid workers they actually use.
§Local provider
use std::time::Duration;
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))
.cleanup_interval(Duration::from_secs(30))
.build()
.unwrap();
let rate = RateLimit::per_second_or_panic(10.0);
let decision = provider.absolute().inc("user-123", &rate, 1);
assert!(matches!(decision, RateLimitDecision::Allowed));Every concrete builder implements RateLimiterBuilder. Shared methods configure windowing,
suppression, and stale-state cleanup. build() returns an Arc and starts cleanup by default;
use disable_cleanup() to opt out and enable_cleanup() to opt back in while configuring the
builder. A provider’s idempotent start_cleanup_loop() and stop_cleanup_loop() methods control
cleanup after construction.
§Time values
Configuration types expose unit-named constructors and explicit getters:
RateLimit:per_second,per_minute,per_hour,per_day,per_week, andper_month, with matchingas_per_*getters; one month is 30 days.WindowSize:seconds,minutes,hours,days,weeks, andmonths, with matchingas_*getters; minute-and-larger getters returnf64.BucketSize:milliseconds,seconds,minutes,hours,days,weeks, andmonths.SuppressionFactorCachePeriod:milliseconds,seconds,minutes,hours, anddays.hybrid::SyncInterval:milliseconds,seconds,minutes, andhours, with matchingas_*getters; second-and-larger getters returnf64.
Provider builders require bucket_size to be less than or equal to window_size; equality is
valid. This relationship is checked by build(), regardless of setter order.
Each constructor has an _or_panic counterpart. Fallible constructors reject zero, invalid
floating-point values, conversion underflow, and overflow. The explicit getters report the
stable semantic unit while leaving internal representation private.
§Redis and hybrid providers
Enable exactly one runtime feature: redis-tokio or redis-smol. Redis 7.2 or newer is
required. Construct the provider directly from the public redis::ConnectionManager:
use trypema::{BucketSize, RateLimiterBuilder, WindowSize};
use trypema::redis::{RedisKey, RedisRateLimiterProvider};
let connection = redis::Client::open("redis://127.0.0.1/")?
.get_connection_manager()
.await?;
let provider = RedisRateLimiterProvider::builder(connection)
.prefix(RedisKey::try_from("my-service")?)
.window_size(WindowSize::minutes_or_panic(1))
.bucket_size(BucketSize::milliseconds_or_panic(10))
.build()?;The hybrid builder additionally exposes sync_interval. Its synchronization worker is always
started and is independent of optional stale-state cleanup.
use trypema::{RateLimiterBuilder, hybrid::{HybridRateLimiterProvider, SyncInterval}};
let provider = HybridRateLimiterProvider::builder(connection)
.sync_interval(SyncInterval::milliseconds_or_panic(10))
.build()?;Redis and hybrid operations accept &RedisKey; local operations accept &str. Redis keys are
validated and never silently sanitized.
§Decisions and conditional updates
Absolute admission returns RateLimitDecision::Allowed or
RateLimitDecision::Rejected. Rejection metadata uses Duration and is best-effort under
bucket coalescing and concurrency. Suppressed admission may return
RateLimitDecision::Suppressed, whose is_allowed field is the admission result.
Conditional update methods return ConditionalSetOutcome. matched distinguishes a
comparator miss from a successful no-op; previous_total and current_total expose totals
before and after the operation. RateLimitComparator::Always requests an unconditional
update through this path.
HistoryPreservation::PreserveNewest consumes oldest buckets first and extends newest
history. HistoryPreservation::PreserveOldest does the reverse. Matched zero targets remove
the key; every matched update replaces its sticky window capacity.
§Managing existing keys
All six limiter variants expose set_rate_limit, delete, and clear. set_rate_limit changes
only an existing key’s sticky capacity and returns its previous effective RateLimit. It
preserves live buckets, timestamps, totals, and declined usage. A missing key returns None; an
equivalent effective rate performs no TTL, cache, activity-metadata, or hybrid-revision writes.
A changed suppressed rate invalidates its cached suppression factor.
delete removes one key and returns its live pre-delete usage in Some: the live total for
absolute limiters and accepted usage (total - total_declined) for suppressed limiters. Existing
zero-usage or cache-only state returns Some(0); missing state returns None. clear removes all
keys belonging to only the called strategy and configured prefix. Local methods are synchronous;
Redis and hybrid methods are asynchronous and return Result. Hybrid state
revisions prevent stale cached totals and limits from undoing these mutations on later Redis
interaction. Concurrent or remote pending increments may still recreate keys afterward.
RateLimitDecision is exhaustive, so callers can match all three variants without a wildcard.
The fields of its Rejected and Suppressed variants remain non-exhaustive, so match those
variants with { .. }:
use trypema::RateLimitDecision;
fn admitted(decision: RateLimitDecision) -> bool {
match decision {
RateLimitDecision::Allowed => true,
RateLimitDecision::Rejected { .. } => false,
RateLimitDecision::Suppressed { is_allowed, .. } => is_allowed,
}
}Other public result structs and TrypemaError remain non-exhaustive.
inc limits are sticky per key: the first increment stores the computed window capacity.
Matched conditional updates replace that stored capacity. A matched target of zero removes the
key. Absolute admission is best-effort under concurrency and may temporarily overshoot.
§Reading live state
Absolute get methods return the live total as u64. Suppressed get methods return
SuppressedRateLimitSnapshot, containing observed usage, declined usage, and the current
suppression factor. Unknown keys return zero-valued results without creating state. Reads may
perform lazy expiration maintenance. Hybrid reads include this instance’s pending local counts;
get_estimate may use initialized local state instead of consulting Redis.
§Name and Biblical Inspiration
The name Trypema is derived from the Koine Greek word “τρυπήματος” (trypematos), meaning “hole” or “opening.” It appears in the phrase “διὰ τρυπήματος ῥαφίδος” (“through the eye of a needle”), spoken by Jesus in three of the four Gospels:
- Matthew 19:24 — “Again I tell you, it is easier for a camel to go through the eye of a needle than for someone who is rich to enter the kingdom of God.”
- Mark 10:25 — “It is easier for a camel to go through the eye of a needle than for someone who is rich to enter the kingdom of God.”
- Luke 18:25 — “Indeed, it is easier for a camel to go through the eye of a needle than for someone who is rich to enter the kingdom of God.”
Just as the eye of a needle is a narrow passage that restricts what can pass through, a rate limiter is a narrow gate that controls the flow of requests into a system.
Modules§
- hybrid
redis-smolorredis-tokio - Hybrid rate limiter implementations (local fast-path + periodic Redis sync).
- local
- In-process rate limiting provider.
- redis
redis-smolorredis-tokio - Redis-backed distributed rate limiter implementations.
Structs§
- Bucket
Size - Bucket coalescing interval stored in milliseconds.
- Conditional
SetOutcome - Result of a conditional total update.
- Hard
Limit Factor - Hard cutoff multiplier for the suppressed strategy.
- Rate
Limit - Per-second rate limit for a key.
- Suppressed
Rate Limit Snapshot - A best-effort snapshot of a suppressed rate limiter’s live state.
- Suppression
Factor Cache Period - Suppression-factor cache period stored in milliseconds.
- Window
Size - Sliding window size stored in seconds.
Enums§
- History
Preservation - Selects which side of an existing sliding-window history is retained when
set_if_preserve_historychanges its total. - Rate
Limit Comparator - Guard condition for conditional writes against a key’s current window total.
- Rate
Limit Decision - Result of a rate limit admission check.
- Trypema
Error - All errors that can occur when using the Trypema rate limiter.
Traits§
- Rate
Limiter Builder - Shared configuration API implemented by every rate-limiter provider builder.