lilydocs
HTTP APIWebSocketConsumer
Güvenlik3 dk okuma

Rate limiting

Redis’in atomik sayaç işlemini bir HTTP guard’a bağlayarak kota ve Retry-After uygulayın.

HTTP rate-limit key’i, kota, pencere ve hata politikası uygulamanıza aittir. lilyrs::redis bu politika için Redis üzerinde atomik fixed-window işlemi sağlar. Bu rehberdeki ApiRateLimitGuard uygulama kodudur.

Bağımlılıklar ve Redis#

Çalışan bir Redis servisi gerekir. Mevcut lilyrs satırına redis feature’ını ve örneğin kullandığı tokio bağımlılığını ekleyin:

Cargo.toml ekleri
lilyrs = { version = "0.1.0", features = ["http-api", "redis"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
TOML
[cache]
mode = "single"
provider = "redis"
redis_url = "redis://127.0.0.1:6379/0"
key_namespace = "users-api"
operation_timeout_secs = 2

redis feature’ı single modu açar. Cache servisi DI üzerinden configuration ve bağlantı yaşam döngüsünü yönetir. Paket adı lily_redis, facade modülü lilyrs::redis olsa da configuration bölümü [cache] olarak kalır.

IP başına kota guard’ı#

rate_limit.rs
use std::{sync::Arc, time::Duration};
use lilyrs::redis::CacheService;
use lilyrs::http_api::{
    CancellationToken, ExecutionCancellation, Extensions, GuardInitError,
    GuardRejection, GuardTrait, HttpErrorCode, Request,
};

pub struct ApiRateLimitGuard { cache: Arc<CacheService> }

fn unavailable() -> GuardRejection {
    GuardRejection::service_unavailable(HttpErrorCode::new("RATE_LIMIT_UNAVAILABLE").unwrap()).unwrap()
}

#[lilyrs::http_api::async_trait::async_trait]
impl GuardTrait for ApiRateLimitGuard {
    async fn new(extensions: Arc<Extensions>) -> Result<Self, GuardInitError> {
        let cache = extensions.get_service::<CacheService>(None).await
            .map_err(|_| GuardInitError::Dependency {
                guard: "ApiRateLimitGuard", reason: "Redis cache unavailable".into(),
            })?;
        Ok(Self { cache })
    }

    async fn can_activate(&self, request: &mut Request, stopping: ExecutionCancellation)
        -> Result<(), GuardRejection>
    {
        let ip = request.client_ip().ok_or_else(unavailable)?;
        // Bu politika, seçili endpoint grubunda IP başına 60 saniyede 100 istektir.
        let key = format!("http:public-api:{ip}");
        let token = CancellationToken::new();
        let operation = self.cache.operation_context(token.clone()).map_err(|_| unavailable())?;
        let work = self.cache.fixed_window_rate_limit_with_context(
            &key, 100, Duration::from_secs(60), &operation,
        );
        tokio::pin!(work);
        let decision = tokio::select! {
            biased;
            _ = stopping.cancelled() => { token.cancel(); work.await }
            result = &mut work => result,
        }.map_err(|_| unavailable())?;
        if decision.allowed() { return Ok(()); }
        Err(GuardRejection::too_many_requests(
            HttpErrorCode::new("RATE_LIMITED").unwrap(), decision.retry_after(),
        ).map_err(|_| unavailable())?)
    }
}

Korunacak action’lara #[guard(ApiRateLimitGuard)] ekleyin. Bu örnek, o endpoint grubunda IP başına 60 saniyede 100 isteği paylaşır. Kota aşılırsa 429 ve backend kararındaki Retry-After, Redis kullanılamıyorsa 503 döner.

Key seçimi#

Kullanıcı başına limit için önce AuthGuard çalıştırıp key’i doğrulanmış principal’dan üretin. IP bazlı limit NAT arkasındaki kullanıcıları ortak sayabilir. Reverse proxy varsa trusted proxy config doğru olmalıdır.

Fixed-window politikası pencere sınırında burst davranışı gösterebilir. Bu davranışı kota seçiminde hesaba katın. max_in_flight_requests eşzamanlı kapasite sınırıdır; zaman başına rate limit değildir.

Cancellation bağlantısı#

HTTP ExecutionCancellation, Redis CancellationToken tipine doğrudan çevrilmez. Örnek ayrı token kurar; durdurma sinyalinde token’ı cancel edip aynı işi await eder. Kopuk bir cancellation task’ı bırakmaz.

Daha kısa ICache::fixed_window_rate_limit(...) yolu configured operation deadline kullanır, fakat HTTP cancellation’ını kendiliğinden bağlamaz.

Bu sayfanın kaynakları v0.1.0

Anlatım, incelenen framework commit’ine dayanır.

HIZLI BAŞLANGIÇ
Dokümantasyon
Kaynak kod