use std::sync::Arc;
use std::time::Instant;
use tokio::time::{Duration, sleep};
use vkteams_bot::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
dotenvy::dotenv().expect("unable to load .env file");
let _guard = otlp::init().map_err(|e| BotError::Otlp(e.into()))?;
println!("ð Starting Rate Limiter Background Refill Demo");
let rate_limiter = Arc::new(RateLimiter::new());
println!("ð§ New Rate Limiter Features:");
println!(" â
Background token refill (no computation during requests)");
println!(" â
Lock-free atomic operations");
println!(" â
Bucket starts with full capacity");
println!(" â
Graceful shutdown support");
println!(" â
High concurrency performance");
demo_immediate_availability(Arc::clone(&rate_limiter)).await?;
demo_background_refill(Arc::clone(&rate_limiter)).await?;
demo_concurrent_performance(Arc::clone(&rate_limiter)).await?;
demo_rate_limiting(Arc::clone(&rate_limiter)).await?;
demo_graceful_shutdown(Arc::clone(&rate_limiter)).await?;
println!("â
All demos completed successfully!");
Ok(())
}
async fn demo_immediate_availability(rate_limiter: Arc<RateLimiter>) -> Result<()> {
println!("ðĶ Demo 1: Immediate Token Availability");
println!(" Bucket starts with full capacity - no delays on startup");
let chat_id = ChatId::from("demo_immediate");
let start = Instant::now();
for i in 1..=5 {
let request_start = Instant::now();
let allowed = rate_limiter.check_rate_limit(&chat_id).await;
let duration = request_start.elapsed();
println!(
" Request {}: {} ({:.2}Ξs)",
i,
if allowed { "â
Allowed" } else { "â Denied" },
duration.as_micros()
);
}
println!(
" Total time for 5 requests: {:.2}ms",
start.elapsed().as_millis()
);
Ok(())
}
async fn demo_background_refill(rate_limiter: Arc<RateLimiter>) -> Result<()> {
println!("ð Demo 2: Background Token Refill");
println!(" Tokens are refilled by background task, not during requests");
let chat_id = ChatId::from("demo_refill");
println!(" Consuming all tokens...");
let mut consumed = 0;
while rate_limiter.check_rate_limit(&chat_id).await {
consumed += 1;
if consumed > 200 {
break;
} }
println!(" Consumed {consumed} tokens");
let allowed = rate_limiter.check_rate_limit(&chat_id).await;
println!(
" Next request: {} (expected - bucket empty)",
if allowed { "â
Allowed" } else { "â Denied" }
);
println!(" Waiting for background refill (2 seconds)...");
sleep(Duration::from_secs(2)).await;
let allowed = rate_limiter.check_rate_limit(&chat_id).await;
println!(
" After refill: {} (background task refilled tokens)",
if allowed { "â
Allowed" } else { "â Denied" }
);
Ok(())
}
async fn demo_concurrent_performance(rate_limiter: Arc<RateLimiter>) -> Result<()> {
println!("⥠Demo 3: High-Performance Concurrent Access");
println!(" Lock-free atomic operations scale with CPU cores");
let rate_limiter = Arc::clone(&rate_limiter);
let start = Instant::now();
let mut handles = vec![];
for thread_id in 0..10 {
let rate_limiter_clone = Arc::clone(&rate_limiter);
let chat_id_clone = ChatId::from(format!("perf_test_{thread_id}"));
let handle = tokio::spawn(async move {
let mut successes = 0;
let thread_start = Instant::now();
for _ in 0..100 {
if rate_limiter_clone.check_rate_limit(&chat_id_clone).await {
successes += 1;
}
}
(thread_id, successes, thread_start.elapsed())
});
handles.push(handle);
}
let mut total_successes = 0;
for handle in handles {
let (thread_id, successes, thread_duration) = handle.await.unwrap();
total_successes += successes;
println!(
" Thread {}: {}/100 requests allowed ({:.2}ms)",
thread_id,
successes,
thread_duration.as_millis()
);
}
let total_duration = start.elapsed();
println!(
" Total: {}/1000 requests in {:.2}ms",
total_successes,
total_duration.as_millis()
);
println!(
" Throughput: {:.0} requests/second",
1000.0 / total_duration.as_secs_f64()
);
Ok(())
}
async fn demo_rate_limiting(rate_limiter: Arc<RateLimiter>) -> Result<()> {
println!("ðĄïļ Demo 4: Rate Limiting Protection");
println!(" Protects against burst requests while allowing normal traffic");
let chat_id = ChatId::from("demo_protection");
println!(" Simulating burst traffic (20 rapid requests):");
let mut allowed_count = 0;
let mut denied_count = 0;
let mut results = String::new();
for i in 1..=20 {
let allowed = rate_limiter.check_rate_limit(&chat_id).await;
if allowed {
allowed_count += 1;
results.push('â
');
} else {
denied_count += 1;
results.push('â');
}
if i % 10 == 0 {
results.push('\n');
}
}
println!("{results}");
println!(" Results: {allowed_count} allowed, {denied_count} denied");
println!(" Rate limiting successfully protected against burst!");
if let Some(stats) = rate_limiter.get_chat_stats(&chat_id).await {
println!(" ð Chat Stats:");
println!(" Total requests: {}", stats.total_requests);
println!(" Allowed: {}", stats.allowed_requests);
println!(" Rate limited: {}", stats.rate_limited_requests);
}
Ok(())
}
async fn demo_graceful_shutdown(rate_limiter: Arc<RateLimiter>) -> Result<()> {
println!("ð Demo 5: Graceful Shutdown");
println!(" Properly cleanup background tasks to prevent resource leaks");
let global_stats = rate_limiter.get_global_stats().await;
println!(" ð Global Stats Before Shutdown:");
println!(" Total requests: {}", global_stats.total_requests);
println!(" Allowed: {}", global_stats.allowed_requests);
println!(" Rate limited: {}", global_stats.rate_limited_requests);
println!(" Shutting down rate limiter...");
rate_limiter.shutdown().await;
println!(" â
Shutdown complete - all background tasks stopped");
Ok(())
}