### Create a Service from an Async Function Source: https://context7.com/tower-rs/tower/llms.txt Use `service_fn` to wrap an async function into a `Service`. The example demonstrates creating a service that echoes input strings. ```rust use tower::{service_fn, ServiceExt, BoxError}; use std::convert::Infallible; #[tokio::main] async fn main() -> Result<(), BoxError> { let mut svc = service_fn(|req: String| async move { println!("handling: {}", req); Ok::(format!("echo: {}", req)) }); // Wait until the service is ready, then call it let response = svc.ready().await?.call("hello".to_string()).await?; assert_eq!(response, "echo: hello"); println!("Response: {}", response); // Output: Response: echo: hello Ok(()) } ``` -------------------------------- ### Install Tower with Features Source: https://context7.com/tower-rs/tower/llms.txt Add Tower to your Cargo.toml, enabling specific middleware features or using "full" for all. ```toml # Enable all middleware tower = { version = "0.5.3", features = ["full"] } # Or enable only what you need tower = { version = "0.5.3", features = ["timeout", "retry", "limit", "buffer", "load-shed", "filter", "steer", "util"] } ``` -------------------------------- ### Mock Service for Testing with `tower-test` Source: https://context7.com/tower-rs/tower/llms.txt Utilize `Mock` and `Handle` from `tower-test` to isolate and test middleware without real I/O. This example demonstrates testing a `TimeoutLayer`. ```rust use tower_test::mock; use tower::{ServiceExt, BoxError}; use tower::timeout::Timeout; use std::time::Duration; #[tokio::test] async fn test_timeout_middleware() { // Create a mock service and a handle to control it let (mut service, mut handle) = mock::spawn_layer::( tower::timeout::TimeoutLayer::new(Duration::from_millis(100)), ); // Allow one request through the mock handle.allow(1); // Send a request let mut call = tokio_test::task::spawn(service.call("ping".to_string())); // The mock has queued the request; pop it off the handle let (request, send_response) = handle.next_request().await.unwrap(); assert_eq!(request, "ping"); // Reply with a response send_response.send_response("pong".to_string()); // The response future resolves let response = call.await.unwrap(); assert_eq!(response, "pong"); } ``` -------------------------------- ### Implement Tower Middleware with Custom Service and Future Source: https://context7.com/tower-rs/tower/llms.txt This example demonstrates the standard Tower middleware pattern by implementing the `Service` trait for a wrapper struct and a custom `Future` using `pin-project-lite` to avoid heap allocation. ```rust use pin_project_lite::pin_project; use std::time::Duration; use std::{ fmt, future::Future, pin::Pin, task::{Context, Poll}, }; use tokio::time::Sleep; use tower::Service; use tower::BoxError; #[derive(Debug, Clone)] pub struct Timeout { inner: S, timeout: Duration, } impl Timeout { pub fn new(inner: S, timeout: Duration) -> Self { Timeout { inner, timeout } } } pin_project! { pub struct ResponseFuture { #[pin] response_future: F, #[pin] sleep: Sleep, } } #[derive(Debug, Default)] pub struct TimeoutError(()); impl fmt::Display for TimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("request timed out") } } impl std::error::Error for TimeoutError {} impl Service for Timeout where S: Service, S::Error: Into, { type Response = S::Response; type Error = BoxError; type Future = ResponseFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx).map_err(Into::into) } fn call(&mut self, request: Request) -> Self::Future { ResponseFuture { response_future: self.inner.call(request), sleep: tokio::time::sleep(self.timeout), } } } impl Future for ResponseFuture where F: Future>, Error: Into, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); if let Poll::Ready(result) = this.response_future.poll(cx) { return Poll::Ready(result.map_err(Into::into)); } if this.sleep.poll(cx).is_ready() { return Poll::Ready(Err(Box::new(TimeoutError(())))); } Poll::Pending } } // Usage: #[tokio::main] async fn main() -> Result<(), BoxError> { use tower::{service_fn, ServiceExt}; let inner = service_fn(|n: u32| async move { Ok::(n * 2) }); let mut svc = Timeout::new(inner, Duration::from_secs(5)); let result = svc.ready().await?.call(21).await?; println!("Result: {}", result); // Result: 42 Ok(()) } ``` -------------------------------- ### `Steer` — Route Requests Between Services Source: https://context7.com/tower-rs/tower/llms.txt Routes each request to one of a list of services, using a `Picker` function that returns an index. The example demonstrates routing based on HTTP method and path. ```APIDOC ## `Steer` — Route Requests Between Services Routes each request to one of a list of services, using a `Picker` function that returns an index. ```rust use tower::steer::Steer; use tower::{ServiceExt, service_fn, BoxError}; use tower::util::BoxService; use http::{Request, Response, StatusCode, Method}; use std::convert::Infallible; #[tokio::main] async fn main() -> Result<(), BoxError> { let root = BoxService::new(service_fn(|_req: Request| async { Ok::<_, Infallible>(Response::new("Hello, World!".to_string())) })); let not_found = BoxService::new(service_fn(|_req: Request| async { Ok::<_, Infallible>( Response::builder() .status(StatusCode::NOT_FOUND) .body(String::new()) .unwrap(), ) })); let mut svc = Steer::new( vec![root, not_found], |req: &Request, _services: &[_]| { if req.method() == Method::GET && req.uri().path() == "/" { 0 // route to `root` } else { 1 // route to `not_found` } }, ); let req = Request::get("/").body(String::new()).unwrap(); let res = svc.ready().await?.call(req).await?; assert_eq!(res.into_body(), "Hello, World!"); let req = Request::get("/missing").body(String::new()).unwrap(); let res = svc.ready().await?.call(req).await?; assert_eq!(res.status(), StatusCode::NOT_FOUND); println!("Routing works correctly!"); Ok(()) } ``` ``` -------------------------------- ### `Filter` and `AsyncFilter` Middleware Source: https://context7.com/tower-rs/tower/llms.txt Conditionally rejects requests using a synchronous or asynchronous predicate before forwarding to the inner service. The `RejectEmpty` example shows how to reject requests that are empty strings. ```APIDOC ## `Filter` and `AsyncFilter` Middleware Conditionally rejects requests using a synchronous or asynchronous predicate before forwarding to the inner service. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use tower::filter::Predicate; #[derive(Clone)] struct RejectEmpty; impl Predicate for RejectEmpty { type Request = String; type Error = BoxError; fn check(&mut self, request: String) -> Result { if request.is_empty() { Err(BoxError::from("request must not be empty")) } else { Ok(request) } } } #[tokio::main] async fn main() -> Result<(), BoxError> { let inner = service_fn(|s: String| async move { Ok::(s.to_uppercase()) }); let mut svc = ServiceBuilder::new() .filter(RejectEmpty) .service(inner); // Valid request let ok = svc.ready().await?.call("hello".to_string()).await?; println!("{}", ok); // HELLO // Rejected request let err = svc.ready().await?.call(String::new()).await; println!("{}", err.unwrap_err()); // request must not be empty Ok(()) } ``` ``` -------------------------------- ### Implement the Layer Trait for Middleware Source: https://context7.com/tower-rs/tower/llms.txt Implement the `Layer` trait to create reusable middleware that wraps existing services. The `LogLayer` example demonstrates logging requests. ```rust use tower_layer::Layer; use tower_service::Service; use std::task::{Context, Poll}; use core::fmt; pub struct LogLayer { target: &'static str, } pub struct LogService { target: &'static str, service: S, } impl Layer for LogLayer { type Service = LogService; fn layer(&self, service: S) -> Self::Service { LogService { target: self.target, service } } } impl Service for LogService where S: Service, Request: fmt::Debug, { type Response = S::Response; type Error = S::Error; type Future = S::Future; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.service.poll_ready(cx) } fn call(&mut self, request: Request) -> Self::Future { println!("[{}] request = {:?}", self.target, request); self.service.call(request) } } ``` -------------------------------- ### `ServiceExt` Combinators — `map_request`, `map_response`, `map_err` Source: https://context7.com/tower-rs/tower/llms.txt Transform requests, responses, or errors inline without writing a full `Service` implementation. Examples show converting request types, formatting response types, and wrapping errors. ```APIDOC ## `ServiceExt` Combinators — `map_request`, `map_response`, `map_err` Transform requests, responses, or errors inline without writing a full `Service` implementation. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; #[tokio::main] async fn main() -> Result<(), BoxError> { // A service that accepts String and returns usize (the length) let inner = service_fn(|s: String| async move { Ok::(s.len()) }); let mut svc = inner // Map request: convert &str to String before sending .map_request(|s: &str| s.to_uppercase()) // Map response: format the usize into a String .map_response(|n| format!("length = {}", n)) // Map error: wrap in a custom message .map_err(|e| BoxError::from(format!("service error: {}", e))); let response = svc.ready().await?.call("hello").await?; println!("{}", response); // length = 5 Ok(()) } ``` ``` -------------------------------- ### `ServiceExt::and_then` / `then` — Chain Async Computation Source: https://context7.com/tower-rs/tower/llms.txt Chain an async function after the service's response future to transform or recover from results. The example shows chaining a user profile lookup after a database query for a user ID. ```APIDOC ## `ServiceExt::and_then` / `then` — Chain Async Computation Chain an async function after the service's response future to transform or recover from results. ```rust use tower::{ServiceExt, BoxError, service_fn}; #[tokio::main] async fn main() -> Result<(), BoxError> { // Service returns a user ID let db = service_fn(|query: &str| async move { println!("querying: {}", query); Ok::(42) }); // Chain a second async lookup after the first one succeeds let mut svc = db.and_then(|user_id: u32| async move { println!("looking up profile for user {}", user_id); Ok::(format!("Alice (id={})", user_id)) }); let profile = svc.ready().await?.call("SELECT id FROM users LIMIT 1").await?; println!("Profile: {}", profile); // Output: // querying: SELECT id FROM users LIMIT 1 // looking up profile for user 42 // Profile: Alice (id=42) Ok(()) } ``` ``` -------------------------------- ### Process Stream of Requests with `ServiceExt::call_all` Source: https://context7.com/tower-rs/tower/llms.txt Drives a stream of requests through a service, producing a stream of responses in order. Ensure the service and stream are compatible. ```rust use tower::{ServiceExt, BoxError, service_fn}; use futures::stream; use futures::StreamExt; #[tokio::main] async fn main() -> Result<(), BoxError> { let svc = service_fn(|n: u32| async move { Ok::(n * n) }); let requests = stream::iter(vec![1u32, 2, 3, 4, 5]); let mut responses = svc.call_all(requests); while let Some(result) = responses.next().await { println!("{}", result?); } // Output: 1 4 9 16 25 Ok(()) } ``` -------------------------------- ### Await Service Readiness with ServiceExt::ready Source: https://context7.com/tower-rs/tower/llms.txt Yields a mutable reference to the service once it is ready to accept a request, respecting backpressure. This is useful for explicitly managing service readiness before sending a request. ```rust use tower::{service_fn, ServiceExt, BoxError}; #[tokio::main] async fn main() -> Result<(), BoxError> { let mut svc = service_fn(|msg: &str| async move { Ok::(msg.to_uppercase()) }); // Explicitly check readiness before calling let response = svc.ready().await?.call("tower").await?; println!("Response: {}", response); // Response: TOWER Ok(()) } ``` -------------------------------- ### Call a Service Once with ServiceExt::oneshot Source: https://context7.com/tower-rs/tower/llms.txt Consumes the service and calls it with a single request, waiting for readiness automatically. This is a convenient way to invoke a service without managing its lifecycle explicitly. ```rust use tower::{service_fn, ServiceExt, BoxError}; #[tokio::main] async fn main() -> Result<(), BoxError> { let svc = service_fn(|n: u32| async move { Ok::(n * 2) }); let result = svc.oneshot(21).await?; assert_eq!(result, 42); println!("Result: {}", result); // Result: 42 Ok(()) } ``` -------------------------------- ### ServiceExt::ready — Await Service Readiness Source: https://context7.com/tower-rs/tower/llms.txt Yields a mutable reference to the service once it is ready to accept a request, respecting backpressure. This is useful for explicitly checking readiness before calling a service. ```APIDOC ## `ServiceExt::ready` — Await Service Readiness Yields a mutable reference to the service once it is ready to accept a request, respecting backpressure. ```rust use tower::{service_fn, ServiceExt, BoxError}; #[tokio::main] async fn main() -> Result<(), BoxError> { let mut svc = service_fn(|msg: &str| async move { Ok::(msg.to_uppercase()) }); // Explicitly check readiness before calling let response = svc.ready().await?.call("tower").await?; println!("Response: {}", response); // Response: TOWER Ok(()) } ``` ``` -------------------------------- ### Annotate ResponseFuture with pin-project Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md Applies the `#[pin_project]` macro from the `pin-project` crate to the `ResponseFuture` struct. This allows for safe pin projection, enabling access to fields like `response_future` and `sleep` through pinned references. ```rust use pin_project::pin_project; #[pin_project] pub struct ResponseFuture { #[pin] response_future: F, #[pin] sleep: Sleep, } ``` -------------------------------- ### Implement Future with pin-project Projection Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md Completes the `Future` implementation for `ResponseFuture` using `pin-project`. The `self.project()` method provides pinned references to the `response_future` and `sleep` fields, allowing them to be polled correctly. ```rust impl Future for ResponseFuture where F: Future>, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // Call the magical `project` method generated by `#[pin_project]`. let this = self.project(); // `project` returns a `__ResponseFutureProjection` but we can ignore // the exact type. It has fields that matches `ResponseFuture` but // maintain pins for fields annotated with `#[pin]`. // `this.response_future` is now a `Pin<&mut F>`. let response_future: Pin<&mut F> = this.response_future; // And `this.sleep` is a `Pin<&mut Sleep>`. let sleep: Pin<&mut Sleep> = this.sleep; // The actual polling logic would go here, using `response_future` and `sleep`. // For example: // match response_future.poll(cx) { // Poll::Ready(result) => Poll::Ready(result), // Poll::Pending => { // match sleep.poll(cx) { // Poll::Ready(_) => Poll::Ready(Err(TimeoutError)), // Assuming TimeoutError exists // Poll::Pending => Poll::Pending, // } // } // } unimplemented!(); // Placeholder for actual logic } } ``` -------------------------------- ### Buffer Requests with `Buffer` Middleware Source: https://context7.com/tower-rs/tower/llms.txt Places a service behind an MPSC channel, making it `Clone` and allowing requests from multiple tasks/threads to be queued and processed serially. The buffer size is configurable. ```rust use tower::buffer::Buffer; use tower::{ServiceExt, BoxError, service_fn}; #[tokio::main] async fn main() -> Result<(), BoxError> { let inner = service_fn(|n: usize| async move { Ok::(n * n) }); // Buffer up to 10 requests; the service is now Clone let svc = Buffer::new(inner, 10); // Spawn multiple tasks each with their own clone let mut handles = vec![]; for i in 0..5 { let mut svc = svc.clone(); handles.push(tokio::spawn(async move { svc.ready().await.unwrap().call(i).await.unwrap() })); } for (i, h) in handles.into_iter().enumerate() { println!("{} squared = {}", i, h.await.unwrap()); } // Output (order may vary): // 0 squared = 0 // 1 squared = 1 // 2 squared = 4 // 3 squared = 9 // 4 squared = 16 Ok(()) } ``` -------------------------------- ### `BoxService` and `BoxCloneService` Source: https://context7.com/tower-rs/tower/llms.txt These utilities provide type erasure for Tower services, allowing them to be stored in collections or passed around without needing to know their concrete type. `BoxService` is for non-cloneable services, while `BoxCloneService` is for cloneable services. ```APIDOC ## `BoxService` and `BoxCloneService` — Type-Erased Services Erase the concrete type of a service into a `Box` for use in collections, structs, or anywhere a concrete type is inconvenient. ### Usage ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use tower::util::{BoxService, BoxCloneService}; use std::time::Duration; struct Request; struct Response { value: u32 } #[tokio::main] async fn main() -> Result<(), BoxError> { // BoxService: Send but not Clone let svc: BoxService = ServiceBuilder::new() .timeout(Duration::from_secs(5)) .concurrency_limit(10) .service_fn(|_req: Request| async { Ok::<_, BoxError>(Response { value: 42 }) }); // BoxCloneService: Send + Clone let cloneable: BoxCloneService = service_fn(|n: u32| async move { Ok::<_, BoxError>(n + 1) }) .boxed_clone(); let c2 = cloneable.clone(); // can be cloned and shared let result = cloneable.oneshot(10).await?; println!("result: {}", result); // result: 11 Ok(()) } ``` ``` -------------------------------- ### ServiceExt::oneshot — Call a Service Once Source: https://context7.com/tower-rs/tower/llms.txt Consumes the service and calls it with a single request, waiting for readiness automatically. This is a convenient way to invoke a service with a single input. ```APIDOC ## `ServiceExt::oneshot` — Call a Service Once Consumes the service and calls it with a single request, waiting for readiness automatically. ```rust use tower::{service_fn, ServiceExt, BoxError}; #[tokio::main] async fn main() -> Result<(), BoxError> { let svc = service_fn(|n: u32| async move { Ok::(n * 2) }); let result = svc.oneshot(21).await?; assert_eq!(result, 42); println!("Result: {}", result); // Result: 42 Ok(()) } ``` ``` -------------------------------- ### Route requests to different services using Steer Source: https://context7.com/tower-rs/tower/llms.txt Employ `tower::steer::Steer` to route incoming requests to one of several services based on a provided `Picker` function. The picker determines the target service index. ```rust use tower::steer::Steer; use tower::{ServiceExt, service_fn, BoxError}; use tower::util::BoxService; use http::{Request, Response, StatusCode, Method}; use std::convert::Infallible; #[tokio::main] async fn main() -> Result<(), BoxError> { let root = BoxService::new(service_fn(|_req: Request| async { Ok::<_, Infallible>(Response::new("Hello, World!".to_string())) })); let not_found = BoxService::new(service_fn(|_req: Request| async { Ok::<_, Infallible>( Response::builder() .status(StatusCode::NOT_FOUND) .body(String::new()) .unwrap(), ) })); let mut svc = Steer::new( vec![root, not_found], |req: &Request, _services: &[_]| { if req.method() == Method::GET && req.uri().path() == "/" { 0 // route to `root` } else { 1 // route to `not_found` } }, ); let req = Request::get("/").body(String::new()).unwrap(); let res = svc.ready().await?.call(req).await?; assert_eq!(res.into_body(), "Hello, World!"); let req = Request::get("/missing").body(String::new()).unwrap(); let res = svc.ready().await?.call(req).await?; assert_eq!(res.status(), StatusCode::NOT_FOUND); println!("Routing works correctly!"); Ok(()) } ``` -------------------------------- ### `tower-test` Mock Service Source: https://context7.com/tower-rs/tower/llms.txt Provides `Mock` and `Handle` for testing Tower services and middleware in isolation. This allows simulating requests and responses without actual I/O operations. ```APIDOC ## `tower-test` — Mock Service for Testing `tower-test` provides `Mock` and `Handle` for testing middleware in isolation without real I/O. ### Usage ```rust use tower_test::mock; use tower::{ServiceExt, BoxError}; use tower::timeout::Timeout; use std::time::Duration; #[tokio::test] async fn test_timeout_middleware() { // Create a mock service and a handle to control it let (mut service, mut handle) = mock::spawn_layer::( tower::timeout::TimeoutLayer::new(Duration::from_millis(100)), ); // Allow one request through the mock handle.allow(1); // Send a request let mut call = tokio_test::task::spawn(service.call("ping".to_string())); // The mock has queued the request; pop it off the handle let (request, send_response) = handle.next_request().await.unwrap(); assert_eq!(request, "ping"); // Reply with a response send_response.send_response("pong".to_string()); // The response future resolves let response = call.await.unwrap(); assert_eq!(response, "pong"); } ``` ``` -------------------------------- ### Enable All Optional Middleware Source: https://github.com/tower-rs/tower/blob/master/tower/README.md Add this to your Cargo.toml to enable all optional middleware provided by Tower. This allows you to use the full suite of Tower's features. ```toml tower = { version = "0.5.1", features = ["full"] } ``` -------------------------------- ### Initial Poll Attempt for ResponseFuture Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md An initial attempt at implementing the `poll` method for `ResponseFuture`. This version tries to poll the inner `response_future` first and returns immediately if it's ready. It encounters a compilation error related to `Pin`ning. ```rust fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { match self.response_future.poll(cx) { Poll::Ready(result) => return Poll::Ready(result), Poll::Pending => {} } todo!() } ``` -------------------------------- ### Prepare futures for timeout logic Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md Initiates the inner service's call and creates a `tokio::time::sleep` future to represent the timeout duration. This sets up the futures for selection. ```rust use tokio::time::sleep; fn call(&mut self, request: Request) -> Self::Future { let response_future = self.inner.call(request); // This variable has type `tokio::time::Sleep`. // // We don't have to clone `self.timeout` as it implements the `Copy` trait. let sleep = tokio::time::sleep(self.timeout); // what to write here? } ``` -------------------------------- ### Transform requests, responses, and errors inline Source: https://context7.com/tower-rs/tower/llms.txt Utilize `ServiceExt` combinators like `map_request`, `map_response`, and `map_err` for concise transformations without implementing a full `Service`. These operate directly on the request, response, or error types. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; #[tokio::main] async fn main() -> Result<(), BoxError> { // A service that accepts String and returns usize (the length) let inner = service_fn(|s: String| async move { Ok::(s.len()) }); let mut svc = inner // Map request: convert &str to String before sending .map_request(|s: &str| s.to_uppercase()) // Map response: format the usize into a String .map_response(|n| format!("length = {}", n)) // Map error: wrap in a custom message .map_err(|e| BoxError::from(format!("service error: {}", e))); let response = svc.ready().await?.call("hello").await?; println!("{}", response); // length = 5 Ok(()) } ``` -------------------------------- ### Implement Future for ResponseFuture Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md Provides a basic `Future` implementation for `ResponseFuture`. This stub is intended to be filled in to poll both the inner response future and the sleep future. ```rust use std::{pin::Pin, future::Future}; impl Future for ResponseFuture where F: Future>, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // What to write here? } } ``` -------------------------------- ### Implement Timeout constructor Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md Provides a constructor function `new` for the `Timeout` struct. It accepts the inner service and timeout duration. ```rust impl Timeout { pub fn new(inner: S, timeout: Duration) -> Self { Timeout { inner, timeout } } } ``` -------------------------------- ### Implement Service for Timeout Middleware Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md Implements the `Service` trait for a `Timeout` struct, using the custom `ResponseFuture`. The `call` method creates and returns the `ResponseFuture` by combining the inner service's future with a new sleep future. ```rust impl Service for Timeout where S: Service, { type Response = S::Response; type Error = S::Error; // Use our new `ResponseFuture` type. type Future = ResponseFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx) } fn call(&mut self, request: Request) -> Self::Future { let response_future = self.inner.call(request); let sleep = tokio::time::sleep(self.timeout); // Create our response future by wrapping the future from the inner // service. ResponseFuture { response_future, sleep, } } } ``` -------------------------------- ### Enable Specific Middleware Features Source: https://github.com/tower-rs/tower/blob/master/tower/README.md Enable only the 'retry' and 'timeout' middleware by specifying them in your Cargo.toml. This approach allows for a more tailored dependency, reducing compile times and binary size. ```toml tower = { version = "0.5.1", features = ["retry", "timeout"] } ``` -------------------------------- ### Type-Erased Services with `BoxService` and `BoxCloneService` Source: https://context7.com/tower-rs/tower/llms.txt Use `BoxService` for send-only services or `BoxCloneService` for clonable services to erase concrete types. This is useful for collections or when a concrete type is inconvenient. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use tower::util::{BoxService, BoxCloneService}; use std::time::Duration; struct Request; struct Response { value: u32 } #[tokio::main] async fn main() -> Result<(), BoxError> { // BoxService: Send but not Clone let svc: BoxService = ServiceBuilder::new() .timeout(Duration::from_secs(5)) .concurrency_limit(10) .service_fn(|_req: Request| async { Ok::<_, BoxError>(Response { value: 42 }) }); // BoxCloneService: Send + Clone let cloneable: BoxCloneService = service_fn(|n: u32| async move { Ok::<_, BoxError>(n + 1) }) .boxed_clone(); let c2 = cloneable.clone(); // can be cloned and shared let result = cloneable.oneshot(10).await?; println!("result: {}", result); // result: 11 Ok(()) } ``` -------------------------------- ### Implement `Service` for `Timeout` Middleware Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md Implement the `Service` trait for a `Timeout` middleware. This involves defining response and error types, and implementing `poll_ready` and `call`. ```rust impl Service for Timeout where S: Service, // Same trait bound like we had on `impl Future for ResponseFuture`. S::Error: Into, { type Response = S::Response; // The error type of `Timeout` is now `BoxError`. type Error = BoxError; type Future = ResponseFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { // Have to map the error type here as well. self.inner.poll_ready(cx).map_err(Into::into) } fn call(&mut self, request: Request) -> Self::Future { let response_future = self.inner.call(request); let sleep = tokio::time::sleep(self.timeout); ResponseFuture { response_future, sleep, } } } ``` -------------------------------- ### `ServiceExt::call_all` Source: https://context7.com/tower-rs/tower/llms.txt Processes a stream of requests through a service, yielding a stream of responses in the same order. This is useful for applying a service to multiple requests concurrently or sequentially. ```APIDOC ## `ServiceExt::call_all` — Process a Stream of Requests Drives a `Stream` of requests through the service, producing a `Stream` of responses in order. ### Usage ```rust use tower::{ServiceExt, BoxError, service_fn}; use futures::stream; use futures::StreamExt; #[tokio::main] async fn main() -> Result<(), BoxError> { let svc = service_fn(|n: u32| async move { Ok::(n * n) }); let requests = stream::iter(vec![1u32, 2, 3, 4, 5]); let mut responses = svc.call_all(requests); while let Some(result) = responses.next().await { println!("{}", result?); } // Output: 1 4 9 16 25 Ok(()) } ``` ``` -------------------------------- ### Handle Overload with `LoadShed` Middleware Source: https://context7.com/tower-rs/tower/llms.txt Immediately returns an error when the inner service is not ready, preventing unbounded queue growth under high load. This is useful for services that cannot handle a large number of concurrent requests. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use tower::load_shed::error::Overloaded; #[tokio::main] async fn main() -> Result<(), BoxError> { let inner = service_fn(|req: &str| async move { Ok::(req.to_uppercase()) }); let mut svc = ServiceBuilder::new() .load_shed() .service(inner); match svc.ready().await?.call("hello").await { Ok(resp) => println!("Response: {}", resp), // Output: Response: HELLO (inner was ready) Err(e) if e.is::() => println!("Service overloaded, try later"), Err(e) => println!("Error: {}", e), } Ok(()) } ``` -------------------------------- ### Implement Timeout Middleware in Rust Source: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md This code defines the `Timeout` middleware, its associated `ResponseFuture`, and error types. It requires `pin-project` and `tokio` for asynchronous operations. The middleware wraps an inner service and returns an error if the inner service does not complete within the specified duration. ```rust use pin_project::pin_project; use std::time::Duration; use std::{ fmt, future::Future, pin::Pin, task::{Context, Poll}, }; use tokio::time::Sleep; use tower::Service; #[derive(Debug, Clone)] struct Timeout { inner: S, timeout: Duration, } impl Timeout { fn new(inner: S, timeout: Duration) -> Self { Timeout { inner, timeout } } } impl Service for Timeout where S: Service, S::Error: Into, { type Response = S::Response; type Error = BoxError; type Future = ResponseFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx).map_err(Into::into) } fn call(&mut self, request: Request) -> Self::Future { let response_future = self.inner.call(request); let sleep = tokio::time::sleep(self.timeout); ResponseFuture { response_future, sleep, } } } #[pin_project] struct ResponseFuture { #[pin] response_future: F, #[pin] sleep: Sleep, } impl Future for ResponseFuture where F: Future>, Error: Into, { type Output = Result; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.project(); match this.response_future.poll(cx) { Poll::Ready(result) => { let result = result.map_err(Into::into); return Poll::Ready(result); } Poll::Pending => {} } match this.sleep.poll(cx) { Poll::Ready(()) => { let error = Box::new(TimeoutError(())); return Poll::Ready(Err(error)); } Poll::Pending => {} } Poll::Pending } } #[derive(Debug, Default)] struct TimeoutError(()); impl fmt::Display for TimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("request timed out") } } impl std::error::Error for TimeoutError {} type BoxError = Box; ``` -------------------------------- ### Implement RateLimit Middleware Source: https://context7.com/tower-rs/tower/llms.txt Enforces a maximum number of requests over a time period. The service becomes unavailable (returns `Poll::Pending`) once the limit is reached until the period resets. Useful for protecting services from being overwhelmed. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), BoxError> { let inner = service_fn(|req: u32| async move { Ok::(format!("processed request #{}", req)) }); // Allow at most 2 requests per second let mut svc = ServiceBuilder::new() .rate_limit(2, Duration::from_secs(1)) .service(inner); // First two requests go through immediately let r1 = svc.ready().await?.call(1).await?; let r2 = svc.ready().await?.call(2).await?; println!("{}", r1); // processed request #1 println!("{}", r2); // processed request #2 // Third request will block until the 1-second window resets let r3 = svc.ready().await?.call(3).await?; println!("{}", r3); // processed request #3 (after ~1s delay) Ok(()) } ``` -------------------------------- ### Implement Retries with `Retry` Middleware and `Policy` Source: https://context7.com/tower-rs/tower/llms.txt Retries failed requests based on a custom `Policy`. The policy determines whether to retry based on the request and result, returning `Some(future)` to retry or `None` to give up. ```rust use tower::retry::Policy; use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use std::future; type Req = &'static str; type Res = &'static str; #[derive(Clone)] struct RetryThreeTimes(usize); impl Policy for RetryThreeTimes { type Future = future::Ready<()>; fn retry(&mut self, _req: &mut Req, result: &mut Result) -> Option { if result.is_err() && self.0 > 0 { self.0 -= 1; println!("retrying, {} attempts left", self.0); Some(future::ready(())) } else { None } } fn clone_request(&mut self, req: &Req) -> Option { Some(*req) } } #[tokio::main] async fn main() -> Result<(), BoxError> { let mut attempt = 0u32; let inner = service_fn(move |req: &'static str| { attempt += 1; async move { if attempt < 3 { Err(BoxError::from(format!("attempt {} failed", attempt))) } else { Ok(req) } } }); let mut svc = ServiceBuilder::new() .retry(RetryThreeTimes(3)) .service(inner); let resp = svc.ready().await?.call("ping").await?; println!("Final response: {}", resp); // Final response: ping Ok(()) } ``` -------------------------------- ### Compose Middleware with ServiceBuilder Source: https://context7.com/tower-rs/tower/llms.txt Chains multiple Layers onto a Service using ServiceBuilder. The first layer added sees the request first. Useful for applying a sequence of common middleware like buffering, concurrency limiting, rate limiting, and timeouts. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use std::time::Duration; use std::convert::Infallible; #[tokio::main] async fn main() -> Result<(), BoxError> { async fn handle(req: &'static str) -> Result<&'static str, BoxError> { println!("processing: {}", req); Ok(req) } let svc = ServiceBuilder::new() .buffer(1024) // buffer up to 1024 in-flight requests .concurrency_limit(32) // max 32 simultaneous requests .rate_limit(100, Duration::from_secs(1)) // max 100 requests per second .timeout(Duration::from_secs(10)) // abort if > 10 seconds .service_fn(handle); let response = svc.oneshot("hello").await?; println!("Response: {}", response); // Output: processing: hello // Response: hello Ok(()) } ``` -------------------------------- ### Implement Timeout Middleware Source: https://context7.com/tower-rs/tower/llms.txt Applies a maximum duration to requests. Returns `tower::BoxError` (which can be downcast to `timeout::error::Elapsed`) if the deadline is exceeded. Use this to prevent requests from hanging indefinitely. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use tower::timeout::error::Elapsed; use std::time::Duration; use tokio::time::sleep; #[tokio::main] async fn main() -> Result<(), BoxError> { let slow_svc = service_fn(|_req: ()| async move { sleep(Duration::from_secs(5)).await; // takes 5 seconds Ok::<&str, BoxError>("done") }); let mut svc = ServiceBuilder::new() .timeout(Duration::from_millis(100)) // timeout after 100ms .service(slow_svc); match svc.ready().await?.call(()).await { Ok(resp) => println!("Response: {}", resp), Err(e) if e.is::() => println!("Request timed out!"), // Output: Request timed out! Err(e) => println!("Other error: {}", e), } Ok(()) } ``` -------------------------------- ### RateLimit Middleware Source: https://context7.com/tower-rs/tower/llms.txt Enforces a maximum number of requests over a time period. The service becomes unavailable (returns `Poll::Pending`) once the limit is reached until the period resets. ```APIDOC ## `RateLimit` Middleware Enforces a maximum number of requests over a time period. The service becomes unavailable (returns `Poll::Pending`) once the limit is reached until the period resets. ```rust use tower::{ServiceBuilder, ServiceExt, BoxError, service_fn}; use std::time::Duration; #[tokio::main] async fn main() -> Result<(), BoxError> { let inner = service_fn(|req: u32| async move { Ok::(format!("processed request #{}", req)) }); // Allow at most 2 requests per second let mut svc = ServiceBuilder::new() .rate_limit(2, Duration::from_secs(1)) .service(inner); // First two requests go through immediately let r1 = svc.ready().await?.call(1).await?; let r2 = svc.ready().await?.call(2).await?; println!("{}", r1); // processed request #1 println!("{}", r2); // processed request #2 // Third request will block until the 1-second window resets let r3 = svc.ready().await?.call(3).await?; println!("{}", r3); // processed request #3 (after ~1s delay) Ok(()) } ``` ``` -------------------------------- ### Chain asynchronous computations after a service response Source: https://context7.com/tower-rs/tower/llms.txt Use `ServiceExt::and_then` to chain an asynchronous function after a service successfully returns a future. This allows for sequential processing or error recovery in async workflows. ```rust use tower::{ServiceExt, BoxError, service_fn}; #[tokio::main] async fn main() -> Result<(), BoxError> { // Service returns a user ID let db = service_fn(|query: &str| async move { println!("querying: {}", query); Ok::(42) }); // Chain a second async lookup after the first one succeeds let mut svc = db.and_then(|user_id: u32| async move { println!("looking up profile for user {}", user_id); Ok::(format!("Alice (id={})", user_id)) }); let profile = svc.ready().await?.call("SELECT id FROM users LIMIT 1").await?; println!("Profile: {}", profile); // Output: // querying: SELECT id FROM users LIMIT 1 // looking up profile for user 42 // Profile: Alice (id=42) Ok(()) } ```