tower-rs / tower

async fn(Request) -> Result<Response, Error>
https://docs.rs/tower
MIT License
3.56k stars 281 forks source link

Rate Limit Layer not Respected #764

Closed cloud303-cholden closed 8 months ago

cloud303-cholden commented 8 months ago

Quick note: I created an issue in axum as well as this involves both tower and axum. I can close whichever of the two makes the most sense.

I am running into an issue with using the RateLimitLayer from tower with axum. I noticed that I can keep sending requests and the rate isn't actually limited. Below is a complete example.

[package]
name = "axum-rate-limit-test"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.7.4"
serde = { version = "1.0.193", features = ["derive"] }
serde_json = { version = "1.0.108", features = ["std"] }
tokio = { version = "1.35.0", features = ["full"] }
tower = { version = "0.4.13", features = ["limit", "buffer"] }
use axum::{
    error_handling::HandleErrorLayer,
    http::StatusCode,
    routing::get,
    BoxError,
    Router,
    Json,
};
use serde::Serialize;
use tokio::net::TcpListener;
use tower::ServiceBuilder;

#[derive(Debug, Serialize)]
pub struct Health {
    pub ok: bool,
}

pub async fn health() -> Result<Json<Health>, (StatusCode, String)> {
    Ok(Json(Health { ok: true }))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let app = Router::new()
        .route("/health", get(health))
        .route_layer(
            ServiceBuilder::new()
                .layer(HandleErrorLayer::new(|err: BoxError| async move {
                    (
                        StatusCode::INTERNAL_SERVER_ERROR,
                        format!("Unhandled error: {}", err),
                    )
                }))
                .buffer(1024)
                .rate_limit(1, tokio::time::Duration::from_secs(5))
        );
    let listener = TcpListener::bind("127.0.0.1:3000")
        .await
        .expect("failed to bind TCP listener");
    axum::serve(listener, app)
        .await
        .expect("failed to serve service");

    Ok(())
}

I expected the request rate to be limited to 1 per 5 seconds. But the below script executes without any rate limiting.

for n in {1..10}; do curl localhost:3000/health; done
jplatte commented 8 months ago

The problem comes from axum, you can close this one.