Skip to content

Commit

Permalink
Remove ReadyService (#68)
Browse files Browse the repository at this point in the history
The value added by having a separate trait is not obvious. Equivalent
behavior can be provided by a `Service` implementation that is always
"ready".
  • Loading branch information
carllerche authored Apr 25, 2018
1 parent 5369879 commit 295ae58
Show file tree
Hide file tree
Showing 10 changed files with 21 additions and 136 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ members = [
"tower-in-flight-limit",
"tower-mock",
"tower-rate-limit",
"tower-ready-service",
"tower-reconnect",
"tower-router",
"tower-service",
Expand Down
1 change: 0 additions & 1 deletion tower-in-flight-limit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ publish = false
[dependencies]
futures = "0.1"
tower-service = { version = "0.1", path = "../tower-service" }
tower-ready-service = { version = "0.1", path = "../tower-ready-service" }

[dev-dependencies]
tower-mock = { version = "0.1", path = "../tower-mock" }
55 changes: 17 additions & 38 deletions tower-in-flight-limit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
//! service.

extern crate futures;
extern crate tower_ready_service;
extern crate tower_service;

use tower_ready_service::ReadyService;
use tower_service::Service;

use futures::{Future, Poll, Async};
Expand Down Expand Up @@ -79,29 +77,6 @@ impl<T> InFlightLimit<T> {
pub fn into_inner(self) -> T {
self.inner
}

fn call2<F, R>(&mut self, f: F) -> ResponseFuture<R>
where F: FnOnce(&mut Self) -> R,
{
// In this implementation, `poll_ready` is not expected to be called
// first (though, it might have been).
if self.state.reserved {
self.state.reserved = false;
} else {
// Try to reserve
if !self.state.shared.reserve() {
return ResponseFuture {
inner: None,
shared: self.state.shared.clone(),
};
}
}

ResponseFuture {
inner: Some(f(self)),
shared: self.state.shared.clone(),
}
}
}

impl<S> Service for InFlightLimit<S>
Expand Down Expand Up @@ -131,20 +106,24 @@ where S: Service
}

fn call(&mut self, request: Self::Request) -> Self::Future {
self.call2(|me| me.inner.call(request))
}
}

impl<S> ReadyService for InFlightLimit<S>
where S: ReadyService
{
type Request = S::Request;
type Response = S::Response;
type Error = Error<S::Error>;
type Future = ResponseFuture<S::Future>;
// In this implementation, `poll_ready` is not expected to be called
// first (though, it might have been).
if self.state.reserved {
self.state.reserved = false;
} else {
// Try to reserve
if !self.state.shared.reserve() {
return ResponseFuture {
inner: None,
shared: self.state.shared.clone(),
};
}
}

fn call(&mut self, request: Self::Request) -> Self::Future {
self.call2(|me| me.inner.call(request))
ResponseFuture {
inner: Some(self.inner.call(request)),
shared: self.state.shared.clone(),
}
}
}

Expand Down
9 changes: 0 additions & 9 deletions tower-ready-service/Cargo.toml

This file was deleted.

Empty file removed tower-ready-service/README.md
Empty file.
3 changes: 0 additions & 3 deletions tower-ready-service/src/lib.rs

This file was deleted.

44 changes: 3 additions & 41 deletions tower-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,47 +189,9 @@ pub trait Service {
/// implementations should take care to not call `poll_ready`. If the
/// service is at capacity and the request is unable to be handled, the
/// returned `Future` should resolve to an error.
fn call(&mut self, req: Self::Request) -> Self::Future;
}

/// An asynchronous function from `Request` to a `Response` that is always ready
/// to process a request.
///
/// `ReadyService` is similar to `Service`, except that it is always able to
/// accept a request. This request may either complete successfully or resolve
/// to an error, i.e., `ReadyService` implementations may handle out of capacity
/// situations by returning a response future that immediately resolves to an
/// error.
///
/// The `Service` trait should be prefered over this one. `ReadyService` should
/// only be used in situations where there is no way to handle back pressure.
/// When usin a `ReadyService` implementation, back pressure needs to be handled
/// via some other strategy, such as limiting the total number of in flight
/// requests.
///
/// One situation in which there is no way to handle back pressure is routing.
/// A router service receives inbound requests and dispatches them to one of N
/// inner services. In this case, one of the inner services may become "not
/// ready" while the others remain ready. It would not be ideal for the router
/// service to flag itself as "not ready" when only one of the inner services is
/// not ready, but there is no way for the router to communicate to the caller
/// which requests will be accepted and which will be rejected. The router
/// service will implement `ReadyService`, indicating to the user that they are
/// responsible for handling back pressure via some other strategy.
pub trait ReadyService {
/// Requests handled by the service.
type Request;

/// Responses returned by the service.
type Response;

/// Errors produced by the service.
type Error;

/// The future response value.
type Future: Future<Item = Self::Response, Error = Self::Error>;

/// Process the request and return the response asynchronously.
///
/// Calling `call` without calling `poll_ready` is permitted. The
/// implementation must be resilient to this fact.
fn call(&mut self, req: Self::Request) -> Self::Future;
}

Expand Down
1 change: 0 additions & 1 deletion tower-util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,3 @@ publish = false
[dependencies]
futures = "0.1"
tower-service = { version = "0.1", path = "../tower-service" }
tower-ready-service = { version = "0.1", path = "../tower-ready-service" }
3 changes: 1 addition & 2 deletions tower-util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Various utility types and functions that are generally with Tower.

extern crate futures;
extern crate tower_ready_service;
extern crate tower_service;

pub mod either;
Expand All @@ -11,5 +10,5 @@ mod service_fn;

pub use boxed::BoxService;
pub use either::EitherService;
pub use service_fn::{ServiceFn, NewServiceFn};
pub use service_fn::{NewServiceFn};
pub use option::OptionService;
40 changes: 0 additions & 40 deletions tower-util/src/service_fn.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,11 @@
use futures::IntoFuture;
use tower_ready_service::ReadyService;
use tower_service::{Service, NewService};

use std::marker::PhantomData;

/// A `Service` implemented by a closure.
#[derive(Debug, Clone)]
pub struct ServiceFn<T, R> {
f: T,
// don't impose Sync on R
_ty: PhantomData<fn() -> R>,
}

/// A `NewService` implemented by a closure.
pub struct NewServiceFn<T> {
f: T,
}

// ===== impl ServiceFn =====

impl<T, R, S> ServiceFn<T, R>
where T: FnMut(R) -> S,
S: IntoFuture,
{
/// Create a new `ServiceFn` backed by the given closure
pub fn new(f: T) -> Self {
ServiceFn {
f,
_ty: PhantomData,
}
}
}

impl<T, R, S> ReadyService for ServiceFn<T, R>
where T: FnMut(R) -> S,
S: IntoFuture,
{
type Request = R;
type Response = S::Item;
type Error = S::Error;
type Future = S::Future;

fn call(&mut self, request: Self::Request) -> Self::Future {
(self.f)(request).into_future()
}
}

// ===== impl NewServiceFn =====

impl<T, N> NewServiceFn<T>
Expand Down

0 comments on commit 295ae58

Please sign in to comment.