Skip to main content

rateguard/
lib.rs

1//! Distributed rate limiting for Rust services: one global limit across a
2//! fleet, no datastore, no network call on the request path.
3//!
4//! Every instance of the service runs a [`Guard`]. The nodes find each other
5//! over UDP and agree, every 200 ms, on how the limit is shared out; each
6//! request is then decided locally, with no I/O and no lock shared with the
7//! network.
8//!
9//! ```no_run
10//! use rateguard::{Decision, Guard};
11//!
12//! # async fn run() -> Result<(), rateguard::Error> {
13//! let guard = Guard::builder()
14//!     .bind("0.0.0.0:7946")
15//!     .advertise("10.0.0.3:7946")
16//!     .seeds(["10.0.0.1:7946", "10.0.0.2:7946"])
17//!     .limit(1_000) // per key, across the whole fleet, per second
18//!     .spawn()?;
19//!
20//! match guard.check("api:tenant-42") {
21//!     Decision::Allow => { /* serve */ }
22//!     Decision::Deny { retry_after } => { /* 429, Retry-After */ }
23//! }
24//! # Ok(())
25//! # }
26//! ```
27//!
28//! The gossip is not encrypted, and by default not authenticated either:
29//! run the nodes on a network you trust, or have them sign it with a
30//! shared secret, see [`Builder::gossip_auth`].
31#![forbid(unsafe_code)]
32#![warn(missing_docs)]
33
34mod classes;
35mod config;
36mod driver;
37mod guard;
38mod key;
39mod key_limits;
40mod limit;
41#[cfg(feature = "metrics")]
42mod metrics;
43mod stats;
44mod sync;
45mod table;
46#[cfg(feature = "tower")]
47pub mod tower;
48mod transport;
49
50pub use config::{Builder, Error, PartitionPolicy};
51pub use guard::{Checked, Decision, Guard};
52pub use key::{key_hash, key_hash_in};
53pub use key_limits::KeyLimit;
54pub use limit::Limit;
55pub use rateguard_proto::auth::{AuthError, GossipAuth, Secret};
56pub use stats::{DeniedKey, KeyStats, RejectedDatagrams, Stats};
57pub use transport::Transport;