Limitación de Concurrencia

El middleware Limitador de Concurrencia puede controlar el número de solicitudes simultáneas. Para detalles específicos de la API, por favor consulte la documentación.

Escenarios de Aplicación

El limitador de concurrencia es particularmente útil en los siguientes escenarios:

  • Protección de Sitios Web con Alto Tráfico: Limita el número de solicitudes procesadas simultáneamente durante picos de tráfico para evitar la sobrecarga del servidor.
  • Control de Operaciones Intensivas en Recursos: Restringe la concurrencia para operaciones que consumen muchos recursos, como subidas de archivos y escrituras en bases de datos.
  • Limitación de Llamadas a APIs de Terceros: Controla el número de solicitudes simultáneas al llamar a servicios externos con límites de tasa.

Funciones Principales

  • Prevenir la Sobrecarga del Servidor: Mantiene la estabilidad del servidor durante picos de tráfico al limitar las solicitudes concurrentes.
  • Mejorar la Fiabilidad del Sistema: Evita caídas del sistema causadas por el agotamiento de recursos.
  • Optimizar la Asignación de Recursos: Asegura que los servicios críticos tengan recursos suficientes para manejar las solicitudes.

Uso

Simplemente agregue el middleware max_concurrency(n) a su ruta, donde n es el número máximo de solicitudes simultáneas permitidas. Las solicitudes que excedan este límite recibirán una respuesta 503 Servicio No Disponible.

Código de Ejemplo

main.rs
Cargo.toml
use std::fs::create_dir_all;
use std::path::Path;

use salvo::prelude::*;

// Handler for serving the index page with upload forms
#[handler]
async fn index(res: &mut Response) {
    res.render(Text::Html(INDEX_HTML));
}

// Handler for processing file uploads with a simulated delay
#[handler]
async fn upload(req: &mut Request, res: &mut Response) {
    // Extract file from the multipart form data
    let file = req.file("file").await;
    // Simulate a long-running operation (10 seconds)
    tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;

    if let Some(file) = file {
        // Generate destination path for the uploaded file
        let dest = format!("temp/{}", file.name().unwrap_or("file"));
        tracing::debug!(dest = %dest, "upload file");

        // Copy file to destination
        if let Err(e) = std::fs::copy(file.path(), Path::new(&dest)) {
            res.status_code(StatusCode::INTERNAL_SERVER_ERROR);
            res.render(Text::Plain(format!("file not found in request: {e}")));
        } else {
            res.render(Text::Plain(format!("File uploaded to {dest}")));
        }
    } else {
        res.status_code(StatusCode::BAD_REQUEST);
        res.render(Text::Plain("file not found in request"));
    }
}

#[tokio::main]
async fn main() {
    // Initialize logging system
    tracing_subscriber::fmt().init();

    // Create temporary directory for file uploads
    create_dir_all("temp").unwrap();

    // Configure router with two upload endpoints:
    // - /limited: Only allows one concurrent upload (with concurrency limiter)
    // - /unlimit: Allows unlimited concurrent uploads
    let router = Router::new()
        .get(index)
        .push(
            Router::new()
                .hoop(max_concurrency(1)) // Limit concurrent requests to 1
                .path("limited")
                .post(upload),
        )
        .push(Router::with_path("unlimit").post(upload));

    // Bind server to port 8698 and start serving
    let acceptor = TcpListener::new("0.0.0.0:8698").bind().await;
    Server::new(acceptor).serve(router).await;
}

// HTML template for the upload forms page
static INDEX_HTML: &str = r#"<!DOCTYPE html>
<html>
    <head>
        <title>Upload file</title>
    </head>
    <body>
        <h1>Upload file</h1>
        <form action="/unlimit" method="post" enctype="multipart/form-data">
            <h3>Unlimit</h3>
            <input type="file" name="file" />
            <input type="submit" value="upload" />
        </form>
        <form action="/limited" method="post" enctype="multipart/form-data">
            <h3>Limited</h3>
            <input type="file" name="file" />
            <input type="submit" value="upload" />
        </form>
    </body>
</html>
"#;