use async_trait::async_trait;
use crate::rate_limit::RateLimit;
use crate::types::RateLimitResult;
pub struct ResilientRateLimit<T> {
inner: T,
}
impl<T: RateLimit> ResilientRateLimit<T> {
pub fn new(inner: T) -> Self {
Self { inner }
}
}
#[async_trait]
impl<T: RateLimit> RateLimit for ResilientRateLimit<T> {
async fn check(
&self,
key: &str,
max_requests: i32,
window_seconds: i32,
) -> crate::Result<RateLimitResult> {
match self.inner.check(key, max_requests, window_seconds).await {
Ok(result) => Ok(result),
Err(e) => {
tracing::warn!(
error = %e,
key,
"L2 rate limit unavailable, falling back to L1 only"
);
Ok(RateLimitResult::allowed_fallback(
max_requests,
window_seconds,
))
}
}
}
async fn peek(
&self,
key: &str,
max_requests: i32,
window_seconds: i32,
) -> crate::Result<RateLimitResult> {
match self.inner.peek(key, max_requests, window_seconds).await {
Ok(result) => Ok(result),
Err(e) => {
tracing::warn!(
error = %e,
key,
"L2 rate limit peek unavailable, returning fallback"
);
Ok(RateLimitResult::allowed_fallback(
max_requests,
window_seconds,
))
}
}
}
async fn reset(&self, key: &str) -> crate::Result<usize> {
self.inner.reset(key).await
}
}