-
Notifications
You must be signed in to change notification settings - Fork 307
Description
Currently if poll_ready
returns Ready
it effectively reserves something (for instance a semaphore token). This means you must be following up with call
next. The only other option is to Drop
the service which however is not always possible.
It was mentioned in the tokio repo that it would be useful to be able to disarm a service (tokio-rs/tokio#898).
This would be particularly useful when one wants to implement an HTTP health check for a load balancer by checking poll_ready
without actually calling.
Example:
pub trait Service<Request> where
<Self::Future as Future>::Output == Result<Self::Response, Self::Error>, {
type Response;
type Error;
type Future: Future;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>>;
fn call(&mut self, req: Request) -> Self::Future;
fn disarm_ready(&mut self) {}
}
And then be used like this:
pub trait HealthcheckServiceExt<Request>: Service<Request> {
fn is_healthy(&mut self) -> bool {
if self.poll_ready().is_ready() {
self.disarm_ready();
true
} else {
false
}
}
}
The proposed new flow would be the following:
poll_ready
must be called. If it'sReady
it must be followed up with eithercall
ordisarm_ready
.call
must not be called withoutpoll_ready
being called beforedisarm_ready
may always be called and should undo whatpoll_ready
didClone
is supposed to either internally calldisarm_ready
or do the same it does (a Clone should always be disarmed)
The latter is already the logic that exists in some layers.
Now obviously it's a bit suboptimal that it means not all services will be able to disarmed so it might also be possible to indicate if something can actually be disarmed. For instance already existing services might just not ever be disarmable until they get retrofitted.