mirror of
https://github.com/tower-rs/tower.git
synced 2025-10-02 15:25:11 +00:00
in-flight-limit: Add missing task notification. (#85)
Previously, there was no notification when capacity is made available by requests completing. This patch fixes the bug. This also switches the tests to use `MockTask` from tokio-test.
This commit is contained in:
parent
679dcbe327
commit
20fb04e3e9
@ -9,4 +9,5 @@ futures = "0.1"
|
|||||||
tower-service = { version = "0.1", path = "../tower-service" }
|
tower-service = { version = "0.1", path = "../tower-service" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
tokio-test = { git = "https://github.com/carllerche/tokio-test" }
|
||||||
tower-mock = { version = "0.1", path = "../tower-mock" }
|
tower-mock = { version = "0.1", path = "../tower-mock" }
|
||||||
|
@ -218,7 +218,14 @@ impl Shared {
|
|||||||
/// request has completed OR the service that made the reservation has
|
/// request has completed OR the service that made the reservation has
|
||||||
/// dropped.
|
/// dropped.
|
||||||
pub fn release(&self) {
|
pub fn release(&self) {
|
||||||
self.curr.fetch_sub(1, SeqCst);
|
let prev = self.curr.fetch_sub(1, SeqCst);
|
||||||
|
|
||||||
|
// Cannot go above the max number of in-flight
|
||||||
|
debug_assert!(prev <= self.max);
|
||||||
|
|
||||||
|
if prev == self.max {
|
||||||
|
self.task.notify();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
extern crate tokio_test;
|
||||||
extern crate tower_mock;
|
extern crate tower_mock;
|
||||||
extern crate tower_in_flight_limit;
|
extern crate tower_in_flight_limit;
|
||||||
extern crate tower_service;
|
extern crate tower_service;
|
||||||
@ -7,9 +8,12 @@ use tower_in_flight_limit::InFlightLimit;
|
|||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
use futures::future::{Future, poll_fn};
|
use futures::future::{Future, poll_fn};
|
||||||
|
use tokio_test::MockTask;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_service_limit_functionality_with_poll_ready() {
|
fn basic_service_limit_functionality_with_poll_ready() {
|
||||||
|
let mut task = MockTask::new();
|
||||||
|
|
||||||
let (mut service, mut handle) =
|
let (mut service, mut handle) =
|
||||||
new_service(2);
|
new_service(2);
|
||||||
|
|
||||||
@ -19,10 +23,12 @@ fn basic_service_limit_functionality_with_poll_ready() {
|
|||||||
poll_fn(|| service.poll_ready()).wait().unwrap();
|
poll_fn(|| service.poll_ready()).wait().unwrap();
|
||||||
let r2 = service.call("hello 2");
|
let r2 = service.call("hello 2");
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(service.poll_ready().unwrap().is_not_ready());
|
assert!(service.poll_ready().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
assert!(!task.is_notified());
|
||||||
|
|
||||||
// The request gets passed through
|
// The request gets passed through
|
||||||
let request = handle.next_request().unwrap();
|
let request = handle.next_request().unwrap();
|
||||||
assert_eq!(*request, "hello 1");
|
assert_eq!(*request, "hello 1");
|
||||||
@ -34,17 +40,21 @@ fn basic_service_limit_functionality_with_poll_ready() {
|
|||||||
request.respond("world 2");
|
request.respond("world 2");
|
||||||
|
|
||||||
// There are no more requests
|
// There are no more requests
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(handle.poll_request().unwrap().is_not_ready());
|
assert!(handle.poll_request().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(r1.wait().unwrap(), "world 1");
|
assert_eq!(r1.wait().unwrap(), "world 1");
|
||||||
|
assert!(task.is_notified());
|
||||||
|
|
||||||
// Another request can be sent
|
// Another request can be sent
|
||||||
poll_fn(|| service.poll_ready()).wait().unwrap();
|
task.enter(|| {
|
||||||
|
assert!(service.poll_ready().unwrap().is_ready());
|
||||||
|
});
|
||||||
|
|
||||||
let r3 = service.call("hello 3");
|
let r3 = service.call("hello 3");
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(service.poll_ready().unwrap().is_not_ready());
|
assert!(service.poll_ready().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -60,6 +70,8 @@ fn basic_service_limit_functionality_with_poll_ready() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_service_limit_functionality_without_poll_ready() {
|
fn basic_service_limit_functionality_without_poll_ready() {
|
||||||
|
let mut task = MockTask::new();
|
||||||
|
|
||||||
let (mut service, mut handle) =
|
let (mut service, mut handle) =
|
||||||
new_service(2);
|
new_service(2);
|
||||||
|
|
||||||
@ -79,7 +91,7 @@ fn basic_service_limit_functionality_without_poll_ready() {
|
|||||||
request.respond("world 2");
|
request.respond("world 2");
|
||||||
|
|
||||||
// There are no more requests
|
// There are no more requests
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(handle.poll_request().unwrap().is_not_ready());
|
assert!(handle.poll_request().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -103,17 +115,19 @@ fn basic_service_limit_functionality_without_poll_ready() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn request_without_capacity() {
|
fn request_without_capacity() {
|
||||||
|
let mut task = MockTask::new();
|
||||||
|
|
||||||
let (mut service, mut handle) =
|
let (mut service, mut handle) =
|
||||||
new_service(0);
|
new_service(0);
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(service.poll_ready().unwrap().is_not_ready());
|
assert!(service.poll_ready().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
let response = service.call("hello");
|
let response = service.call("hello");
|
||||||
|
|
||||||
// There are no more requests
|
// There are no more requests
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(handle.poll_request().unwrap().is_not_ready());
|
assert!(handle.poll_request().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -122,18 +136,20 @@ fn request_without_capacity() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reserve_capacity_without_sending_request() {
|
fn reserve_capacity_without_sending_request() {
|
||||||
|
let mut task = MockTask::new();
|
||||||
|
|
||||||
let (mut s1, mut handle) =
|
let (mut s1, mut handle) =
|
||||||
new_service(1);
|
new_service(1);
|
||||||
|
|
||||||
let mut s2 = s1.clone();
|
let mut s2 = s1.clone();
|
||||||
|
|
||||||
// Reserve capacity in s1
|
// Reserve capacity in s1
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s1.poll_ready().unwrap().is_ready());
|
assert!(s1.poll_ready().unwrap().is_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Service 2 cannot get capacity
|
// Service 2 cannot get capacity
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s2.poll_ready().unwrap().is_not_ready());
|
assert!(s2.poll_ready().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -142,50 +158,54 @@ fn reserve_capacity_without_sending_request() {
|
|||||||
let request = handle.next_request().unwrap();
|
let request = handle.next_request().unwrap();
|
||||||
request.respond("world");
|
request.respond("world");
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s2.poll_ready().unwrap().is_not_ready());
|
assert!(s2.poll_ready().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
r1.wait().unwrap();
|
r1.wait().unwrap();
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s2.poll_ready().unwrap().is_ready());
|
assert!(s2.poll_ready().unwrap().is_ready());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn service_drop_frees_capacity() {
|
fn service_drop_frees_capacity() {
|
||||||
|
let mut task = MockTask::new();
|
||||||
|
|
||||||
let (mut s1, _handle) =
|
let (mut s1, _handle) =
|
||||||
new_service(1);
|
new_service(1);
|
||||||
|
|
||||||
let mut s2 = s1.clone();
|
let mut s2 = s1.clone();
|
||||||
|
|
||||||
// Reserve capacity in s1
|
// Reserve capacity in s1
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s1.poll_ready().unwrap().is_ready());
|
assert!(s1.poll_ready().unwrap().is_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Service 2 cannot get capacity
|
// Service 2 cannot get capacity
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s2.poll_ready().unwrap().is_not_ready());
|
assert!(s2.poll_ready().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
drop(s1);
|
drop(s1);
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s2.poll_ready().unwrap().is_ready());
|
assert!(s2.poll_ready().unwrap().is_ready());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn response_error_releases_capacity() {
|
fn response_error_releases_capacity() {
|
||||||
|
let mut task = MockTask::new();
|
||||||
|
|
||||||
let (mut s1, mut handle) =
|
let (mut s1, mut handle) =
|
||||||
new_service(1);
|
new_service(1);
|
||||||
|
|
||||||
let mut s2 = s1.clone();
|
let mut s2 = s1.clone();
|
||||||
|
|
||||||
// Reserve capacity in s1
|
// Reserve capacity in s1
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s1.poll_ready().unwrap().is_ready());
|
assert!(s1.poll_ready().unwrap().is_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -196,33 +216,35 @@ fn response_error_releases_capacity() {
|
|||||||
|
|
||||||
r1.wait().unwrap_err();
|
r1.wait().unwrap_err();
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s2.poll_ready().unwrap().is_ready());
|
assert!(s2.poll_ready().unwrap().is_ready());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn response_future_drop_releases_capacity() {
|
fn response_future_drop_releases_capacity() {
|
||||||
|
let mut task = MockTask::new();
|
||||||
|
|
||||||
let (mut s1, _handle) =
|
let (mut s1, _handle) =
|
||||||
new_service(1);
|
new_service(1);
|
||||||
|
|
||||||
let mut s2 = s1.clone();
|
let mut s2 = s1.clone();
|
||||||
|
|
||||||
// Reserve capacity in s1
|
// Reserve capacity in s1
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s1.poll_ready().unwrap().is_ready());
|
assert!(s1.poll_ready().unwrap().is_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
// s1 sends the request, then s2 is able to get capacity
|
// s1 sends the request, then s2 is able to get capacity
|
||||||
let r1 = s1.call("hello");
|
let r1 = s1.call("hello");
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s2.poll_ready().unwrap().is_not_ready());
|
assert!(s2.poll_ready().unwrap().is_not_ready());
|
||||||
});
|
});
|
||||||
|
|
||||||
drop(r1);
|
drop(r1);
|
||||||
|
|
||||||
with_task(|| {
|
task.enter(|| {
|
||||||
assert!(s2.poll_ready().unwrap().is_ready());
|
assert!(s2.poll_ready().unwrap().is_ready());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -235,8 +257,3 @@ fn new_service(max: usize) -> (InFlightLimit<Mock>, Handle) {
|
|||||||
let service = InFlightLimit::new(service, max);
|
let service = InFlightLimit::new(service, max);
|
||||||
(service, handle)
|
(service, handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_task<F: FnOnce() -> U, U>(f: F) -> U {
|
|
||||||
use futures::future::{Future, lazy};
|
|
||||||
lazy(|| Ok::<_, ()>(f())).wait().unwrap()
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user