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}