Skip to content

Disarming Service after successful poll_ready #408

@mitsuhiko

Description

@mitsuhiko

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's Ready it must be followed up with either call or disarm_ready.
  • call must not be called without poll_ready being called before
  • disarm_ready may always be called and should undo what poll_ready did
  • Clone is supposed to either internally call disarm_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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-serviceArea: The tower `Service` traitC-feature-requestCategory: A feature request, i.e: not implemented / a PR.I-needs-decisionIssues in need of decision.P-mediumMedium priority

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions