1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
//! # A more in-depth guide to `governor`
//!
//! Governor is a fork/rewrite/rebranding of the
//! [`ratelimit_meter`](https://crates.io/crates/ratelimit_meter) and
//! [`ratelimit_futures`](https://crates.io/crates/ratelimit_futures)
//! crates. Many of the things that worked there still work here, and
//! this guide's aim is to help you accomplish them.
//!
//! # Constructing a rate limiter
//!
//! If you're used to `ratelimit_meter` parlance, both "direct" and
//! "keyed" rate limiters are supported. Direct rate limiters keep only a
//! single state (such as the rate of outflowing e-mail
//! conversations). Keyed rate limiters on the other hand have one rate
//! limiting state per key: e.g., the flow of API requests made by each
//! customer.
//!
//! Construction of rate limiters is designed to be mostly infallible via
//! types that ensure you can't pass the wrong parameters, mostly around
//! non-zero integers. Since that kind of checking is a little tedious to
//! do by hand, `governor` makes heavy use of the
//! [`NonZeroU32`][std::num::NonZeroU32] type.
//!
//! To conveniently construct these nonzero numbers yourself, use the
//! [`nonzero!`](../../nonzero_ext/macro.nonzero.html) macro.
//!
//! #### Quotas
//!
//! Each rate limiter has a quota: A rate of elements (could be API
//! requests, emails, phone calls... anything really) per unit of time (second,
//! minute, hour). Specify these in a [`Quota`][crate::Quota] object like so:
//!
//! ```rust
//! # use nonzero_ext::*;
//! use governor::Quota;
//! Quota::per_second(nonzero!(20u32));
//! ```
//!
//! #### Constructing a direct rate limiter
//!
//! To make a direct rate limiter, you have to construct a quota, as
//! above; and then use this to construct the rate limiter itself. In
//! `std` mode, this is easily accomplished like so:
//!
//! ```rust
//! # #[cfg(feature = "std")] fn main() {
//! # use nonzero_ext::*;
//! # use governor::{RateLimiter, Quota};
//! RateLimiter::direct(Quota::per_second(nonzero!(50u32)));
//! # } #[cfg(not(feature = "std"))] fn main() {}
//! ```
//!
//! In `no_std` mode, there are is no default monotonic (or system)
//! clock available. To effectively limit rates, you will have to
//! either use the provided "fake" clock (which must be manually
//! advanced, and is mainly useful for tests), or implement the
//! `Clock` trait for your platform. Once that decision is made,
//! constructing a rate limiter with an explicit clock works like
//! this:
//!
//! ```rust
//! # use nonzero_ext::*;
//! # use governor::{clock::FakeRelativeClock, RateLimiter, Quota};
//! let clock = FakeRelativeClock::default();
//! RateLimiter::direct_with_clock(Quota::per_second(nonzero!(50u32)), &clock);
//! ```
//!
//! #### Constructing a keyed rate limiter
//!
//! For a keyed rate limiter, you have to specify the type of the key:
//! Otherwise they function exactly as their direct counterpart. They are
//! stored in a hash-table like state store. The default in `std` mode is
//! provided by the [`dashmap`](https://docs.rs/dashmap) crate:
//!
//! ```rust
//! # use nonzero_ext::*;
//! # use governor::{RateLimiter, Quota};
//! let lim = RateLimiter::keyed(Quota::per_second(nonzero!(50u32)));
//! lim.check_key(&"cus_1").unwrap(); // one key
//! lim.check_key(&"cus_2").unwrap(); // another!
//! ```
//!
//! You can supply your own keyed state store implementation if you
//! wish. That requires implementing the
//! [KeyedStateStore][crate::state::keyed::KeyedStateStore] trait, and optionally the
//! [ShrinkableKeyedStateStore][crate::state::keyed::ShrinkableKeyedStateStore] trait.
//!
//! # Type signatures for rate limiters
//!
//! Rate limiters tend to be long-lived, and need to be stored
//! somewhere - sometimes in struct fields, or even just to pass in
//! function arguments. The [`crate::RateLimiter`] type signatures
//! tend to be pretty unwieldy for that, so this crate exports a pair
//! of handy type aliases, [`crate::DefaultDirectRateLimiter`] and
//! [`crate::DefaultKeyedRateLimiter`].
//!
//! Here's an example for embedding a direct rate limiter in a struct:
//!
//! ```rust
//! # use governor::DefaultDirectRateLimiter;
//! struct MyApiClient {
//! limiter: DefaultDirectRateLimiter,
//! }
//! ```
//!
//! If you need to provide a different clock, or a different
//! implementation of the keyed state, you will still have to fall
//! back to the regular type.
//!
//! # Data ownership and references to rate limiters
//!
//! `governor`'s rate limiter state is not hidden behind an [interior
//! mutability](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html)
//! pattern, and so it is perfectly valid to have multiple references
//! to a rate limiter in a program. Since its state lives in
//! [`AtomicU64`][std::sync::atomic::AtomicU64] integers (which do not
//! implement [`Clone`]), the rate limiters themselves can not be
//! cloned.
//!
//! # Usage in multiple threads
//!
//! Sharing references to a rate limiter across threads is completely
//! OK (rate limiters are Send and Sync by default), but there is a
//! problem: A rate limiter's lifetime might be up before a thread
//! ends, which would invalidate the reference.
//!
//! So, to use a rate limiter in multiple threads without lifetime
//! issues, there are two equally valid strategies:
//!
//! #### `crossbeam` scoped tasks
//!
//! The `crossbeam` crate's
//! [scopes](https://docs.rs/crossbeam/0.7.3/crossbeam/thread/struct.Scope.html#method.spawn)
//! allow code to guarantee that a thread spawned in a scope
//! terminates before the scope terminates. This allows using
//!
//! stack-allocated variables. Here is an example test using crossbeam
//! scopes:
//!
//! ```rust
//! # use crossbeam;
//! # use nonzero_ext::*;
//! # use governor::{clock::FakeRelativeClock, RateLimiter, Quota};
//! # use std::time::Duration;
//!
//! let mut clock = FakeRelativeClock::default();
//! let lim = RateLimiter::direct_with_clock(Quota::per_second(nonzero!(20u32)), &clock);
//! let ms = Duration::from_millis(1);
//!
//! crossbeam::scope(|scope| {
//! for _i in 0..20 {
//! scope.spawn(|_| {
//! assert_eq!(Ok(()), lim.check());
//! });
//! }
//! })
//! .unwrap();
//! ```
//!
//! #### Wrapping the limiter in an [`Arc`][std::sync::Arc]
//!
//! The other method uses only the standard library: Wrapping the rate
//! limiter in an [`Arc`][std::sync::Arc] will keep the limiter alive
//! for as long as there exist references to it - perfect for passing
//! to threads.
//!
//! In this example, note that we're cloning the
//! [`Arc`][std::sync::Arc]; the rate limiter stays identical (rate
//! limiters do not implement [`Clone`]), only its references are
//! duplicated (and refcounts incremented atomically).
//!
//! Note also the placement of the clone: As we're creating a `move`
//! closure, a binding that can be moved into the closure must be set
//! up outside it. Rustc will be upset at you if you try to clone the
//! Arc too early outside the closure, or even inside it. See the
//! [`Arc`][std::sync::Arc] docs for some more usage examples.
//!
//! ```rust
//! # #[cfg(feature = "std")] fn main() {
//! # use nonzero_ext::*;
//! # use governor::{RateLimiter, Quota};
//! # use std::time::Duration;
//! # use std::sync::Arc;
//! # use std::thread;
//! let bucket = Arc::new(RateLimiter::direct(Quota::per_second(nonzero!(20u32))));
//! for _i in 0..20 {
//! let bucket = Arc::clone(&bucket);
//! thread::spawn(move || {
//! assert_eq!(Ok(()), bucket.check());
//! })
//! .join()
//! .unwrap();
//! }
//! # } #[cfg(not(feature = "std"))] fn main() {}
//! ```
//!