Announcing Tower — A library for writing robust network services with Rust.
Tower (Github) has been a bit of an open secret for a while now, but it has been getting some mentions recently after the Rust all hands, so I thought I would write a more formal post to talk about it, the goals, and the short term roadmap.
Tower is a library for writing robust network services with Rust. It is being built in service of the Conduit proxy, which is using the Tokio ecosystem to build the world’s smallest, fastest, most secure network proxy. Roughly, the main components are:
- A service abstraction for request / response based protocols.
- A collection of protocol agnostic middleware.
Tower will also provide a batteries included experience for implementing HTTP and gRPC services.
tower-webwill be a server web framework, focusing on ergonomics and ease of use. Allowing users to rapidly build out production ready HTTP services based on the tower stack.
tower-grpcis a gRPC client and server based on the tower stack. It takes a proto file and generates the stubs for you. It uses Prost (a really great library) for the protobuf part.
And, of course, Tower is built on top of the Tokio stack.
Extracting what is common across protocols
The fundamental premise upon which Tower is built is that all client and server implementations for request / response based protocols require the same set of functionality in order to be robust and production ready. The goal of Tower is to extract all of this commonality into a set of abstractions and components.
This is not a new idea. There are similar projects for other languages that have proven out that this idea works out. The most prominent is Finagle for Scala.
The first step is to define a core abstraction: the service.
This service trait provides the abstraction representing a handling a single request. Both the request and the response types are generic. One way to think of a
Service is as an asynchronous function of
If you are thinking that this is similar to
tokio-service then you would be right. That was a first attempt, but it was put on hold as Tokio itself was developed.
An HTTP hello world service might look like this:
Now, HTTP libraries like Hyper can run any service that implements the tower trait for the HTTP request and response types.
If you are thinking that this is a lot of boilerplate, you would be right again. This is where
tower-web comes in, I will get to that soon.
Because services are now implemented using a standard trait, these implementations can be decorated to add further behavior. This is where middleware comes in.
A piece of middleware is any type that takes a
T: Service and implements
Service itself adding some sort of additional behavior.
Tower already comes with a set of middleware that can be used with any protocol and mixed / matched to cover the needs of the application. Some middleware that we already wrote includes:
tower-timeouttakes a service and requires the response to complete within the specified duration. If it takes too long, the request is timed out.
tower-balancedistributes the incoming requests across a number of inner service instances.
tower-bufferspecifies a max number of concurrent requests that the inner service can handle. When the max is reached, it will stop accepting new requests until in-flight ones complete.
Having to manually define service implementations and configure middleware stacks requires a lot of boilerplate and boilerplate isn’t fun. The thing is, in most cases, an application is going to be built on a pretty standard set of middleware. To make it as easy as possible to just write applications, Tower will provide a batteries included, ergonomic web framework.
When using Tower Web, it will be trivial to get your web service defined and out of the box it will be production grade, building on top of the Tokio and Tower stacks.
The code for Tower Web has not yet been opened up. There is still a bit of churn there, but keep an eye out for more announcements really soon!
Tower gRPC has already been opened up and can be found here. We use it in Conduit. The easiest way to get a feel for how it works is to look at the examples. You start with a gRPC proto file, which defines the service. Then, as part of
cargo build you convert the proto file into Rust stubs. From there, you can use the generated gRPC client or implement the server. This is what the server half looks like:
Also, Tower gRPC is a pure Rust implementation. So there is no binding to external C or C++ libraries. It uses h2 under the hood for the HTTP/2.0 protocol layer.
How to get involved
If you look at the various READMEs for the linked crates, you will find some discouraging language recommending that you don’t use it. The Tower stack is still in its very early days, but we are using it today successfully in Conduit. An initial, official, release of Tower will hopefully happen by summer. That said, if you are willing to pull up your sleeves, and become a contributor, you should feel free to start using it today.