Update tower-load to std::future (#321)

This bumps tower-load to 0.3.0-alpha.1
This commit is contained in:
Jon Gjengset 2019-09-09 09:22:49 -04:00 committed by GitHub
parent db116d1937
commit f8097a60f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 137 additions and 94 deletions

View File

@ -9,7 +9,7 @@ members = [
# "tower-hedge",
"tower-layer",
# "tower-limit",
# "tower-load",
"tower-load",
# "tower-load-shed",
# "tower-reconnect",
# "tower-retry",

View File

@ -1,3 +1,7 @@
# 0.3.0-alpha.1
- Move to `std::future`
# 0.1.0 (unreleased)
- Initial release

View File

@ -8,13 +8,13 @@ name = "tower-load"
# - README.md
# - Update CHANGELOG.md.
# - Create "v0.1.x" git tag.
version = "0.1.0"
version = "0.3.0-alpha.1"
authors = ["Tower Maintainers <team@tower-rs.com>"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/tower-rs/tower"
homepage = "https://github.com/tower-rs/tower"
documentation = "https://docs.rs/tower-load/0.1.0"
documentation = "https://docs.rs/tower-load/0.3.0-alpha.1"
description = """
Strategies for measuring the load of a service
"""
@ -23,11 +23,13 @@ edition = "2018"
publish = false
[dependencies]
futures = "0.1.26"
futures-core-preview = "0.3.0-alpha.18"
log = "0.4.1"
tokio-timer = "0.2.4"
tower-service = "0.2.0"
tower-discover = "0.1.0"
tokio-timer = "0.3.0-alpha.4"
tower-service = "0.3.0-alpha.1"
tower-discover = { version = "0.3.0-alpha.1", path = "../tower-discover" }
pin-project = "0.4.0-alpha.9"
[dev-dependencies]
tokio-executor = "0.1.2"
tokio-test = "0.2.0-alpha.4"
futures-util-preview = "0.3.0-alpha.18"

View File

@ -1,12 +1,18 @@
//! A constant `Load` implementation. Primarily useful for testing.
use futures::{try_ready, Async, Poll};
use futures_core::ready;
use pin_project::pin_project;
use std::{
pin::Pin,
task::{Context, Poll},
};
use tower_discover::{Change, Discover};
use tower_service::Service;
use crate::Load;
/// Wraps a type so that `Load::load` returns a constant value.
#[pin_project]
pub struct Constant<T, M> {
inner: T,
load: M,
@ -38,8 +44,8 @@ where
type Error = S::Error;
type Future = S::Future;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.inner.poll_ready()
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, req: Request) -> Self::Future {
@ -48,20 +54,24 @@ where
}
/// Proxies `Discover` such that all changes are wrapped with a constant load.
impl<D: Discover, M: Copy> Discover for Constant<D, M> {
impl<D: Discover + Unpin, M: Copy> Discover for Constant<D, M> {
type Key = D::Key;
type Service = Constant<D::Service, M>;
type Error = D::Error;
/// Yields the next discovery change set.
fn poll(&mut self) -> Poll<Change<D::Key, Self::Service>, D::Error> {
fn poll_discover(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Change<D::Key, Self::Service>, D::Error>> {
use self::Change::*;
let change = match try_ready!(self.inner.poll()) {
Insert(k, svc) => Insert(k, Constant::new(svc, self.load)),
let this = self.project();
let change = match ready!(Pin::new(this.inner).poll_discover(cx))? {
Insert(k, svc) => Insert(k, Constant::new(svc, *this.load)),
Remove(k) => Remove(k),
};
Ok(Async::Ready(change))
Poll::Ready(Ok(change))
}
}

View File

@ -1,4 +1,10 @@
use futures::{try_ready, Future, Poll};
use futures_core::ready;
use pin_project::pin_project;
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
/// Attaches `I`-typed instruments to `V` typed values.
///
@ -31,12 +37,10 @@ pub trait Instrument<H, V>: Clone {
pub struct NoInstrument;
/// Attaches a `I`-typed instruments to the result of an `F`-typed `Future`.
#[pin_project]
#[derive(Debug)]
pub struct InstrumentFuture<F, I, H>
where
F: Future,
I: Instrument<H, F::Item>,
{
pub struct InstrumentFuture<F, I, H> {
#[pin]
future: F,
handle: Option<H>,
instrument: I,
@ -44,11 +48,7 @@ where
// ===== impl InstrumentFuture =====
impl<F, I, H> InstrumentFuture<F, I, H>
where
F: Future,
I: Instrument<H, F::Item>,
{
impl<F, I, H> InstrumentFuture<F, I, H> {
/// Wraps a future, instrumenting its value if successful.
pub fn new(instrument: I, handle: H, future: F) -> Self {
InstrumentFuture {
@ -59,18 +59,18 @@ where
}
}
impl<F, I, H> Future for InstrumentFuture<F, I, H>
impl<F, I, H, T, E> Future for InstrumentFuture<F, I, H>
where
F: Future,
I: Instrument<H, F::Item>,
F: Future<Output = Result<T, E>>,
I: Instrument<H, T>,
{
type Item = I::Output;
type Error = F::Error;
type Output = Result<I::Output, E>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let rsp = try_ready!(self.future.poll());
let h = self.handle.take().expect("handle");
Ok(self.instrument.instrument(h, rsp).into())
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let rsp = ready!(this.future.poll(cx))?;
let h = this.handle.take().expect("handle");
Poll::Ready(Ok(this.instrument.instrument(h, rsp)))
}
}

View File

@ -1,6 +1,6 @@
//! Abstractions and utilties for measuring a service's load.
#![doc(html_root_url = "https://docs.rs/tower-load/0.1.0")]
#![doc(html_root_url = "https://docs.rs/tower-load/0.3.0-alpha.1")]
#![deny(missing_docs)]
#![deny(rust_2018_idioms)]
#![deny(warnings)]

View File

@ -2,8 +2,13 @@
use super::{Instrument, InstrumentFuture, NoInstrument};
use crate::Load;
use futures::{try_ready, Async, Poll};
use futures_core::ready;
use log::trace;
use pin_project::pin_project;
use std::{
pin::Pin,
task::{Context, Poll},
};
use std::{
sync::{Arc, Mutex},
time::{Duration, Instant},
@ -45,7 +50,9 @@ pub struct PeakEwma<S, I = NoInstrument> {
}
/// Wraps a `D`-typed stream of discovery updates with `PeakEwma`.
#[pin_project]
pub struct PeakEwmaDiscover<D, I = NoInstrument> {
#[pin]
discover: D,
decay_ns: f64,
default_rtt: Duration,
@ -108,21 +115,25 @@ where
type Service = PeakEwma<D::Service, I>;
type Error = D::Error;
fn poll(&mut self) -> Poll<Change<D::Key, Self::Service>, D::Error> {
let change = match try_ready!(self.discover.poll()) {
fn poll_discover(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Change<D::Key, Self::Service>, D::Error>> {
let this = self.project();
let change = match ready!(this.discover.poll_discover(cx))? {
Change::Remove(k) => Change::Remove(k),
Change::Insert(k, svc) => {
let peak_ewma = PeakEwma::new(
svc,
self.default_rtt,
self.decay_ns,
self.instrument.clone(),
*this.default_rtt,
*this.decay_ns,
this.instrument.clone(),
);
Change::Insert(k, peak_ewma)
}
};
Ok(Async::Ready(change))
Poll::Ready(Ok(change))
}
}
@ -156,8 +167,8 @@ where
type Error = S::Error;
type Future = InstrumentFuture<S::Future, I, Handle>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: Request) -> Self::Future {
@ -293,12 +304,16 @@ fn nanos(d: Duration) -> f64 {
#[cfg(test)]
mod tests {
use futures::{future, Future, Poll};
use futures_util::future;
use std::{
future::Future,
task::{Context, Poll},
};
use std::{
sync::{Arc, Mutex},
time::{Duration, Instant},
};
use tokio_executor::enter;
use tokio_test::{assert_ready, assert_ready_ok};
use tokio_timer::clock;
use super::*;
@ -307,10 +322,10 @@ mod tests {
impl Service<()> for Svc {
type Response = ();
type Error = ();
type Future = future::FutureResult<(), ()>;
type Future = future::Ready<Result<(), ()>>;
fn poll_ready(&mut self) -> Poll<(), ()> {
Ok(().into())
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), ()>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, (): ()) -> Self::Future {
@ -332,8 +347,7 @@ mod tests {
let time = Arc::new(Mutex::new(Instant::now()));
let clock = clock::Clock::new_with_now(Now(time.clone()));
let mut enter = enter().expect("enter");
clock::with_default(&clock, &mut enter, |_| {
clock::with_default(&clock, || {
let svc = PeakEwma::new(
Svc,
Duration::from_millis(10),
@ -360,8 +374,8 @@ mod tests {
let time = Arc::new(Mutex::new(Instant::now()));
let clock = clock::Clock::new_with_now(Now(time.clone()));
let mut enter = enter().expect("enter");
clock::with_default(&clock, &mut enter, |_| {
clock::with_default(&clock, || {
tokio_test::task::mock(|cx| {
let mut svc = PeakEwma::new(
Svc,
Duration::from_millis(20),
@ -371,19 +385,19 @@ mod tests {
assert_eq!(svc.load(), Cost(20.0 * NANOS_PER_MILLI));
*time.lock().unwrap() += Duration::from_millis(100);
let rsp0 = svc.call(());
let mut rsp0 = svc.call(());
assert!(svc.load() > Cost(20.0 * NANOS_PER_MILLI));
*time.lock().unwrap() += Duration::from_millis(100);
let rsp1 = svc.call(());
let mut rsp1 = svc.call(());
assert!(svc.load() > Cost(40.0 * NANOS_PER_MILLI));
*time.lock().unwrap() += Duration::from_millis(100);
let () = rsp0.wait().unwrap();
let () = assert_ready_ok!(Pin::new(&mut rsp0).poll(cx));
assert_eq!(svc.load(), Cost(400_000_000.0));
*time.lock().unwrap() += Duration::from_millis(100);
let () = rsp1.wait().unwrap();
let () = assert_ready_ok!(Pin::new(&mut rsp1).poll(cx));
assert_eq!(svc.load(), Cost(200_000_000.0));
// Check that values decay as time elapses
@ -392,6 +406,7 @@ mod tests {
*time.lock().unwrap() += Duration::from_secs(10);
assert!(svc.load() < Cost(100_000.0));
})
});
}

View File

@ -2,8 +2,13 @@
use super::{Instrument, InstrumentFuture, NoInstrument};
use crate::Load;
use futures::{try_ready, Async, Poll};
use futures_core::ready;
use pin_project::pin_project;
use std::sync::Arc;
use std::{
pin::Pin,
task::{Context, Poll},
};
use tower_discover::{Change, Discover};
use tower_service::Service;
@ -21,8 +26,10 @@ pub struct PendingRequests<S, I = NoInstrument> {
struct RefCount(Arc<()>);
/// Wraps `inner`'s services with `PendingRequests`.
#[pin_project]
#[derive(Debug)]
pub struct PendingRequestsDiscover<D, I = NoInstrument> {
#[pin]
discover: D,
instrument: I,
}
@ -69,8 +76,8 @@ where
type Error = S::Error;
type Future = InstrumentFuture<S::Future, I, Handle>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready()
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self, req: Request) -> Self::Future {
@ -109,15 +116,19 @@ where
type Error = D::Error;
/// Yields the next discovery change set.
fn poll(&mut self) -> Poll<Change<D::Key, Self::Service>, D::Error> {
fn poll_discover(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<Change<D::Key, Self::Service>, D::Error>> {
use self::Change::*;
let change = match try_ready!(self.discover.poll()) {
Insert(k, svc) => Insert(k, PendingRequests::new(svc, self.instrument.clone())),
let this = self.project();
let change = match ready!(this.discover.poll_discover(cx))? {
Insert(k, svc) => Insert(k, PendingRequests::new(svc, this.instrument.clone())),
Remove(k) => Remove(k),
};
Ok(Async::Ready(change))
Poll::Ready(Ok(change))
}
}
@ -132,16 +143,17 @@ impl RefCount {
#[cfg(test)]
mod tests {
use super::*;
use futures::{future, Future, Poll};
use futures_util::future;
use std::task::{Context, Poll};
struct Svc;
impl Service<()> for Svc {
type Response = ();
type Error = ();
type Future = future::FutureResult<(), ()>;
type Future = future::Ready<Result<(), ()>>;
fn poll_ready(&mut self) -> Poll<(), ()> {
Ok(().into())
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), ()>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, (): ()) -> Self::Future {
@ -160,10 +172,10 @@ mod tests {
let rsp1 = svc.call(());
assert_eq!(svc.load(), Count(2));
let () = rsp0.wait().unwrap();
let () = tokio_test::block_on(rsp0).unwrap();
assert_eq!(svc.load(), Count(1));
let () = rsp1.wait().unwrap();
let () = tokio_test::block_on(rsp1).unwrap();
assert_eq!(svc.load(), Count(0));
}
@ -183,12 +195,12 @@ mod tests {
let rsp = svc.call(());
assert_eq!(svc.load(), Count(1));
let i0 = rsp.wait().unwrap();
let i0 = tokio_test::block_on(rsp).unwrap();
assert_eq!(svc.load(), Count(1));
let rsp = svc.call(());
assert_eq!(svc.load(), Count(2));
let i1 = rsp.wait().unwrap();
let i1 = tokio_test::block_on(rsp).unwrap();
assert_eq!(svc.load(), Count(2));
drop(i1);