pub struct RateLimiter { /* private fields */ }Expand description
A token-bucket rate limiter.
Construct one with RateLimiter::new, then gate work with
try_acquire / try_acquire_one.
The bucket starts full (a burst of up to capacity is allowed immediately).
Time is a plain u64 in any monotonic unit you choose (commonly
milliseconds); refill_interval uses that same unit. The limiter never reads
the clock itself — pass now to each method.
RateLimiter is not internally synchronized. Share one across threads by
wrapping it in your own Mutex/lock.
Implementations§
Source§impl RateLimiter
impl RateLimiter
Sourcepub const fn new(
capacity: u64,
refill_amount: u64,
refill_interval: u64,
) -> Self
pub const fn new( capacity: u64, refill_amount: u64, refill_interval: u64, ) -> Self
Creates a limiter that holds up to capacity tokens and adds
refill_amount tokens every refill_interval time units.
The bucket starts full. capacity, refill_amount, and
refill_interval are each clamped to a minimum of 1 (a zero interval
would never refill and would divide by zero).
Examples found in repository?
14fn main() {
15 // Allow bursts of up to 5, refilling 1 token every 200ms.
16 let mut limiter = RateLimiter::new(5, 1, 200);
17 let start = Instant::now();
18
19 for i in 0..15 {
20 let now = start.elapsed().as_millis() as u64;
21
22 if limiter.try_acquire_one(now) {
23 println!(
24 "[{now:>4}ms] request {i:>2}: allowed ({} left)",
25 limiter.available(now)
26 );
27 } else {
28 let wait = limiter.retry_after(now, 1).unwrap_or(0);
29 println!("[{now:>4}ms] request {i:>2}: throttled, retry after {wait}ms");
30 }
31
32 std::thread::sleep(std::time::Duration::from_millis(80));
33 }
34}Sourcepub const fn refill_amount(&self) -> u64
pub const fn refill_amount(&self) -> u64
Returns how many tokens are added on each refill.
Sourcepub const fn refill_interval(&self) -> u64
pub const fn refill_interval(&self) -> u64
Returns the refill interval, in the caller’s time unit.
Sourcepub fn available(&mut self, now: u64) -> u64
pub fn available(&mut self, now: u64) -> u64
Returns the number of tokens available at now, after refilling.
Examples found in repository?
14fn main() {
15 // Allow bursts of up to 5, refilling 1 token every 200ms.
16 let mut limiter = RateLimiter::new(5, 1, 200);
17 let start = Instant::now();
18
19 for i in 0..15 {
20 let now = start.elapsed().as_millis() as u64;
21
22 if limiter.try_acquire_one(now) {
23 println!(
24 "[{now:>4}ms] request {i:>2}: allowed ({} left)",
25 limiter.available(now)
26 );
27 } else {
28 let wait = limiter.retry_after(now, 1).unwrap_or(0);
29 println!("[{now:>4}ms] request {i:>2}: throttled, retry after {wait}ms");
30 }
31
32 std::thread::sleep(std::time::Duration::from_millis(80));
33 }
34}Sourcepub fn try_acquire(&mut self, now: u64, tokens: u64) -> bool
pub fn try_acquire(&mut self, now: u64, tokens: u64) -> bool
Tries to take tokens tokens at now. Returns true and consumes them
if enough are available, otherwise returns false and consumes nothing.
A request for more than capacity tokens can never succeed.
Sourcepub fn try_acquire_one(&mut self, now: u64) -> bool
pub fn try_acquire_one(&mut self, now: u64) -> bool
Tries to take a single token at now.
Examples found in repository?
14fn main() {
15 // Allow bursts of up to 5, refilling 1 token every 200ms.
16 let mut limiter = RateLimiter::new(5, 1, 200);
17 let start = Instant::now();
18
19 for i in 0..15 {
20 let now = start.elapsed().as_millis() as u64;
21
22 if limiter.try_acquire_one(now) {
23 println!(
24 "[{now:>4}ms] request {i:>2}: allowed ({} left)",
25 limiter.available(now)
26 );
27 } else {
28 let wait = limiter.retry_after(now, 1).unwrap_or(0);
29 println!("[{now:>4}ms] request {i:>2}: throttled, retry after {wait}ms");
30 }
31
32 std::thread::sleep(std::time::Duration::from_millis(80));
33 }
34}Sourcepub fn retry_after(&mut self, now: u64, tokens: u64) -> Option<u64>
pub fn retry_after(&mut self, now: u64, tokens: u64) -> Option<u64>
Returns how long to wait, from now, until tokens tokens are available.
Returns Some(0) if they are available now, and None if tokens
exceeds capacity (the bucket can never hold that many). Useful for a
Retry-After hint. This refills the bucket but does not consume anything.
Examples found in repository?
14fn main() {
15 // Allow bursts of up to 5, refilling 1 token every 200ms.
16 let mut limiter = RateLimiter::new(5, 1, 200);
17 let start = Instant::now();
18
19 for i in 0..15 {
20 let now = start.elapsed().as_millis() as u64;
21
22 if limiter.try_acquire_one(now) {
23 println!(
24 "[{now:>4}ms] request {i:>2}: allowed ({} left)",
25 limiter.available(now)
26 );
27 } else {
28 let wait = limiter.retry_after(now, 1).unwrap_or(0);
29 println!("[{now:>4}ms] request {i:>2}: throttled, retry after {wait}ms");
30 }
31
32 std::thread::sleep(std::time::Duration::from_millis(80));
33 }
34}Trait Implementations§
Source§impl Clone for RateLimiter
impl Clone for RateLimiter
Source§fn clone(&self) -> RateLimiter
fn clone(&self) -> RateLimiter
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for RateLimiter
Source§impl Debug for RateLimiter
impl Debug for RateLimiter
impl Eq for RateLimiter
Source§impl PartialEq for RateLimiter
impl PartialEq for RateLimiter
Source§fn eq(&self, other: &RateLimiter) -> bool
fn eq(&self, other: &RateLimiter) -> bool
self and other values to be equal, and is used by ==.