Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rate Limiting #1181

Open
NexVeridian opened this issue Jan 15, 2025 · 3 comments
Open

Rate Limiting #1181

NexVeridian opened this issue Jan 15, 2025 · 3 comments
Labels
controller enhancement New feature or request

Comments

@NexVeridian
Copy link
Contributor

Tower Governor some built in ones that might be useful

[PeerIpKeyExtractor]: this is the default, it uses the peer IP address of the request.
[SmartIpKeyExtractor]: Looks for common IP identification headers usually provided by reverse proxies in order(x-forwarded-for,x-real-ip, forwarded) and falls back to the peer IP address.
[GlobalKeyExtractor]: uses the same key for all incoming requests

for a global extractor we should use tower govern or tower
tower example, from here:

use axum::{error_handling::HandleErrorLayer, http::StatusCode, routing::get, BoxError, Router};
use std::{net::SocketAddr, time::Duration};
use tower::{buffer::BufferLayer, limit::RateLimitLayer, ServiceBuilder};

#[tokio::main]
async fn main() {
    let app = Router::new().route("/", get(|| async {})).layer(
        ServiceBuilder::new()
            .layer(HandleErrorLayer::new(|err: BoxError| async move {
                (
                    StatusCode::INTERNAL_SERVER_ERROR,
                    format!("Unhandled error: {}", err),
                )
            }))
            .layer(BufferLayer::new(1024))
            .layer(RateLimitLayer::new(5, Duration::from_secs(1))),
    );

    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
}

tower govern also has custom_key_bearer which could be used for per user rate limiting, instead of by ip, by grabbing the jwt token then calling the database and adding the user id to the custom_key_bearer, but this option has a database call

@NexVeridian NexVeridian added the enhancement New feature or request label Jan 15, 2025
@jondot
Copy link
Contributor

jondot commented Jan 15, 2025

Thanks!
Would you like to create a configuration section for this and add a PR for people to enable rate limiting via configuration?

The middleware stack is here:
https://github.com/loco-rs/loco/blob/master/src/controller/middleware/mod.rs#L72

Middleware configuration here:
https://github.com/loco-rs/loco/blob/master/src/controller/middleware/mod.rs#L171

Example middleware limit_payload here:
https://github.com/loco-rs/loco/blob/master/src/controller/middleware/limit_payload.rs

@kaplanelad
Copy link
Contributor

@NexVeridian
What about distributed service? The rate limit counters are stored in a single process, which creates a problem when scaling out across multiple instances.

@NexVeridian
Copy link
Contributor Author

Yeah that's true

which creates a problem when scaling out across multiple instances.

I did find this comment by the library creator talking about that

So maybe have both a per instances rate limit, and a database based rate limiter if guaranteeing a low limit is important for that route

But a database based rate limiter would probably have to be manually implemented, I haven't been able to find a widely used maintained redis based tower middleware for rate limiting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
controller enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants