by_loco/controller/middleware/
timeout.rs

1//! Timeout Request Middleware.
2//!
3//! This middleware applies a timeout to requests processed by the application.
4//! The timeout duration is configurable and defined via the
5//! [`TimeoutRequestMiddleware`] configuration. The middleware ensures that
6//! requests do not run beyond the specified timeout period, improving the
7//! overall performance and responsiveness of the application.
8//!
9//! If a request exceeds the specified timeout duration, the middleware will
10//! return a `408 Request Timeout` status code to the client, indicating that
11//! the request took too long to process.
12use std::time::Duration;
13
14use axum::Router as AXRouter;
15use serde::{Deserialize, Serialize};
16use serde_json::json;
17use tower_http::timeout::TimeoutLayer;
18
19use crate::{app::AppContext, controller::middleware::MiddlewareLayer, Result};
20
21/// Timeout middleware configuration
22#[derive(Debug, Clone, Deserialize, Serialize)]
23pub struct TimeOut {
24    #[serde(default)]
25    pub enable: bool,
26    // Timeout request in milliseconds
27    #[serde(default = "default_timeout")]
28    pub timeout: u64,
29}
30
31impl Default for TimeOut {
32    fn default() -> Self {
33        serde_json::from_value(json!({})).unwrap()
34    }
35}
36
37fn default_timeout() -> u64 {
38    5_000
39}
40
41impl MiddlewareLayer for TimeOut {
42    /// Returns the name of the middleware.
43    fn name(&self) -> &'static str {
44        "timeout_request"
45    }
46
47    /// Checks if the timeout middleware is enabled.
48    fn is_enabled(&self) -> bool {
49        self.enable
50    }
51
52    fn config(&self) -> serde_json::Result<serde_json::Value> {
53        serde_json::to_value(self)
54    }
55
56    /// Applies the timeout middleware to the application router.
57    ///
58    /// This method wraps the provided [`AXRouter`] in a [`TimeoutLayer`],
59    /// ensuring that requests exceeding the specified timeout duration will
60    /// be interrupted.
61    fn apply(&self, app: AXRouter<AppContext>) -> Result<AXRouter<AppContext>> {
62        Ok(app.layer(TimeoutLayer::new(Duration::from_millis(self.timeout))))
63    }
64}