#![cfg(feature = "std-time")]
use rate_guard::{
Nanos, StdTimeSource, RateLimit, RateLimitError,
limits::TokenBucketBuilder,
};
use std::time::Duration;
use std::thread::sleep;
fn main() {
let bucket = TokenBucketBuilder::builder()
.capacity(100)
.refill_amount(10)
.refill_every(Duration::from_millis(300))
.with_time(StdTimeSource::new())
.with_precision::<Nanos>()
.build()
.unwrap();
println!("Starting token bucket (sync)");
for i in 0..20 {
match acquire_with_retry(&bucket, 20, 5) {
Ok(()) => println!("[{:02}] Allowed", i),
Err(e) => println!("[{:02}] Failed: {}", i, e),
}
sleep(Duration::from_millis(50));
}
println!("Done.");
}
fn acquire_with_retry(
limiter: &impl RateLimit,
tokens: u64,
max_retries: usize,
) -> Result<(), RateLimitError> {
for attempt in 0..max_retries {
match limiter.try_acquire_verbose(tokens) {
Ok(()) => return Ok(()),
Err(RateLimitError::InsufficientCapacity { retry_after, .. }) => {
if attempt < max_retries - 1 {
println!(
"Attempt {}: Insufficient capacity, retrying in {:?}...",
attempt + 1,
retry_after.as_nanos()
);
sleep(retry_after);
} else {
return Err(RateLimitError::InsufficientCapacity {
acquiring: tokens,
available: 0,
retry_after,
});
}
}
Err(RateLimitError::ContentionFailure) => {
std::thread::yield_now(); }
Err(e) => return Err(e),
}
}
Err(RateLimitError::ContentionFailure)
}