Trait Service
trait Service<Request>
An asynchronous function from a Request to a Response.
The Service trait is a simplified interface making it easy to write
network applications in a modular and reusable way, decoupled from the
underlying protocol. It is one of Tower's fundamental abstractions.
Functional
A Service is a function of a Request. It immediately returns a
Future representing the eventual completion of processing the
request. The actual request processing may happen at any time in the
future, on any thread or executor. The processing may depend on calling
other services. At some point in the future, the processing will complete,
and the Future will resolve to a response or error.
At a high level, the Service::call function represents an RPC request. The
Service value can be a server or a client.
Server
An RPC server implements the Service trait. Requests received by the
server over the network are deserialized and then passed as an argument to the
server value. The returned response is sent back over the network.
As an example, here is how an HTTP request is processed by a server:
# use Pin;
# use ;
# use Future;
# use Service;
use ;
;
Client
A client consumes a service by using a Service value. The client may
issue requests by invoking call and passing the request as an argument.
It then receives the response by waiting for the returned future.
As an example, here is how a Redis request would be issued:
let client = new
.connect
.unwrap;
let resp = client.call.await?;
// Wait for the future to resolve
println!;
Middleware / Layer
More often than not, all the pieces needed for writing robust, scalable network applications are the same no matter the underlying protocol. By unifying the API for both clients and servers in a protocol agnostic way, it is possible to write middleware that provide these pieces in a reusable way.
Take timeouts as an example:
use Service;
use Layer;
use FutureExt;
use Future;
use ;
use Duration;
use Pin;
use fmt;
use Error;
// Our timeout service, which wraps another service and
// adds a timeout to its response future.
// The error returned if processing a request timed out
;
// We can implement `Service` for `Timeout<T>` if `T` is a `Service`
// A layer for wrapping services in `Timeout`
;
The above timeout implementation is decoupled from the underlying protocol and is also decoupled from client or server concerns. In other words, the same timeout middleware could be used in either a client or a server.
Backpressure
Calling a Service which is at capacity (i.e., it is temporarily unable to process a
request) should result in an error. The caller is responsible for ensuring
that the service is ready to receive the request before calling it.
Service provides a mechanism by which the caller is able to coordinate
readiness. Service::poll_ready returns Ready if the service expects that
it is able to process a request.
Be careful when cloning inner services
Services are permitted to panic if call is invoked without obtaining Poll::Ready(Ok(()))
from poll_ready. You should therefore be careful when cloning services for example to move
them into boxed futures. Even though the original service is ready, the clone might not be.
Therefore this kind of code is wrong and might panic:
# use Pin;
# use ;
# use Future;
# use Service;
#
You should instead use std::mem::replace to take the service that was ready:
# use Pin;
# use ;
# use Future;
# use Service;
#
Associated Types
type ResponseResponses given by the service.
type ErrorErrors produced by the service.
type Future: TraitBound { trait_: Path { path: "Future", id: Id(3), args: Some(AngleBracketed { args: [], constraints: [AssocItemConstraint { name: "Output", args: None, binding: Equality(Type(ResolvedPath(Path { path: "Result", id: Id(4), args: Some(AngleBracketed { args: [Type(QualifiedPath { name: "Response", args: None, self_type: Generic("Self"), trait_: Some(Path { path: "", id: Id(5), args: None }) }), Type(QualifiedPath { name: "Error", args: None, self_type: Generic("Self"), trait_: Some(Path { path: "", id: Id(5), args: None }) })], constraints: [] }) }))) }] }) }, generic_params: [], modifier: None }The future response value.
Required Methods
fn poll_ready(self: &mut Self, cx: &mut Context<'_>) -> Poll<Result<(), <Self as >::Error>>Returns
Poll::Ready(Ok(()))when the service is able to process requests.If the service is at capacity, then
Poll::Pendingis returned and the task is notified when the service becomes ready again. This function is expected to be called while on a task. Generally, this can be done with a simplefutures::future::poll_fncall.If
Poll::Ready(Err(_))is returned, the service is no longer able to service requests and the caller should discard the service instance.Once
poll_readyreturnsPoll::Ready(Ok(())), a request may be dispatched to the service usingcall. Until a request is dispatched, repeated calls topoll_readymust return eitherPoll::Ready(Ok(()))orPoll::Ready(Err(_)).Note that
poll_readymay reserve shared resources that are consumed in a subsequent invocation ofcall. Thus, it is critical for implementations to not assume thatcallwill always be invoked and to ensure that such resources are released if the service is dropped beforecallis invoked or the future returned bycallis dropped before it is polled.fn call(self: &mut Self, req: Request) -> <Self as >::FutureProcess the request and return the response asynchronously.
This function is expected to be callable off task. As such, implementations should take care to not call
poll_ready.Before dispatching a request,
poll_readymust be called and returnPoll::Ready(Ok(())).Panics
Implementations are permitted to panic if
callis invoked without obtainingPoll::Ready(Ok(()))frompoll_ready.
Implementors
impl<S, Request> Service for Box<S>impl<'a, S, Request> Service for &'a mut S