Limitation de Concurrence

Le middleware Limiteur de Concurrence permet de contrôler le nombre de requêtes simultanées. Pour les détails spécifiques de l'API, veuillez consulter la documentation.

Scénarios d'Application

Le limiteur de concurrence est particulièrement utile dans les situations suivantes :

  • Protection des Sites Web à Fort Trafic : Limite le nombre de requêtes traitées simultanément lors de pics de trafic pour éviter la surcharge du serveur.
  • Contrôle des Opérations à Forte Consommation de Ressources : Restreint la concurrence pour les opérations gourmandes en ressources, telles que les téléchargements de fichiers et les écritures en base de données.
  • Limitation des Appels aux API Tierces : Contrôle le nombre de requêtes simultanées lors de l'appel à des services externes avec des limites de débit.

Fonctions Principales

  • Prévenir la Surcharge du Serveur : Maintient la stabilité du serveur pendant les pics de trafic en limitant les requêtes simultanées.
  • Améliorer la Fiabilité du Système : Évite les plantages du système causés par l'épuisement des ressources.
  • Optimiser l'Allocation des Ressources : Garantit que les services critiques disposent de ressources suffisantes pour traiter les requêtes.

Utilisation

Ajoutez simplement le middleware max_concurrency(n) à votre route, où n est le nombre maximum de requêtes simultanées autorisées. Les requêtes dépassant cette limite recevront une réponse 503 Service Indisponible.

Exemple de Code

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>
"#;