Skip to content
tezvyn:
Menu

Rust's Tower Service: One Trait for Clients, Servers, and Middleware

Source: docs.rsHardHow cards are made

Tower's Service trait is a universal API for async requests. It models any 'request -> future<response>' flow, unifying clients, servers, and middleware. Use it for HTTP servers or database clients. The footgun: ignoring poll_ready bypasses backpressure.

Why it exists

To create a single, unified abstraction for all asynchronous request-response operations in a network application. This avoids writing separate logic for clients, servers, and middleware components, promoting code reuse and composability for concerns like logging, timeouts, or rate limiting.

The mental model

Think of a Service as a single, asynchronous function: async fn(Request) -> Result<Response, Error>. It's a black box that takes one thing and will eventually give you another thing back, or an error. This simple contract is powerful enough to represent an entire HTTP server, a database client connection, or a single piece of middleware like a rate limiter.

How it works

The Service trait has two key methods: poll_ready and call. First, you call poll_ready to ask, "Can you handle a request right now?". This is the backpressure mechanism. If it returns Poll::Ready(Ok(())), the service is ready. Only then should you invoke call(request). call consumes the request and immediately returns a Future. You then .await this future to get the final Response or Error. The key rule is you cannot call call again until the future from poll_ready resolves.

When to use it

Use Tower and its Service trait when building networked applications in Rust that require modularity and robustness. It's the foundation of popular frameworks like Axum (for web servers) and is used in clients for databases like Redis. It's ideal when you need to compose layers of functionality, such as adding logging, metrics, and timeouts to a core business logic service.

When not to use it

For very simple, one-off network clients or servers where you don't foresee needing layers of middleware, the overhead of the Service trait and its ecosystem might be unnecessary. A direct tokio::net implementation could be simpler if you don't need composability. It's also not intended for synchronous, blocking operations.

One canonical example

An HTTP server is a Service<Request>. A timeout layer is also a Service that wraps another Service. When a request arrives, it first hits the timeout Service. The timeout service calls the inner HTTP Service, but wraps the returned Future in a race with a timer. If the timer wins, the timeout service returns an error. If the inner service's future wins, it passes the response through. This demonstrates how services compose.

Interview question

What is the primary function of the `poll_ready` method in a Tower `Service` implementation?

  • a.To signal backpressure, indicating whether the service can accept a new request without becoming overloaded.Correct
  • b.To prepare the service's internal buffers and allocate resources for an upcoming request.
  • c.To synchronously process a request and return an immediate response if the service is idle.
  • d.To establish and verify the underlying network connection before any data exchange occurs.
Why?

The card explicitly states that `poll_ready` is "the backpressure mechanism" used to ask, "Can you handle a request right now?", which directly relates to the service's capacity. Option C is incorrect because `call` returns a Future, not an immediate response, and `poll_ready` does not process the request itself.

Just read this? Test yourself on what you have been reading.

Read the original → docs.rs

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on rust — each one lists the topics its interview covers.

See open roles