#![cfg(feature = "tokio-time")]
use rate_guard::{
Nanos, TokioTimeSource, RateLimit, RateLimitError,
limits::TokenBucketBuilder,
};
use tokio::time::{ Duration , sleep };
const MAX_RETRIES: usize = 5;
#[tokio::main]
async fn main() {
let bucket = TokenBucketBuilder::builder()
.capacity(100)
.refill_amount(10)
.refill_every(Duration::from_millis(100))
.with_time(TokioTimeSource::new())
.with_precision::<Nanos>()
.build()
.expect("Failed to build token bucket");
println!("Starting token bucket (async with retry)");
for i in 0..20 {
let success = acquire_with_retry(&bucket, 20, MAX_RETRIES).await;
match success {
Ok(()) => println!("[{:02}] Allowed", i),
Err(e) => println!("[{:02}] Failed after retries: {}", i, e),
}
}
println!("Done.");
}
async 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).await;
} else {
return Err(RateLimitError::InsufficientCapacity {
acquiring: tokens,
available: 0,
retry_after,
});
}
}
Err(e) => return Err(e),
}
}
unreachable!() }