Skip to content

Commit

Permalink
fix(client): schedule interval to clear expired idle connections
Browse files Browse the repository at this point in the history
Currently only works if Client is built with a `Handle`, and not a
custome executor, since a `Handle` is required to create a tokio
Interval.
  • Loading branch information
seanmonstar committed Feb 28, 2018
1 parent 1223fc2 commit 727b747
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 23 deletions.
34 changes: 15 additions & 19 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,33 +90,15 @@ impl<C, B> Client<C, B> {
Exec::Executor(..) => panic!("Client not built with a Handle"),
}
}
}


impl<C, B> Client<C, B>
where C: Connect,
B: Stream<Error=::Error>,
B::Item: AsRef<[u8]>,
{
// Create a new client with a specific connector.
#[inline]
fn configured(config: Config<C, B>, exec: Exec) -> Client<C, B> {
let client = Client {
Client {
connector: Rc::new(config.connector),
executor: exec,
h1_writev: config.h1_writev,
pool: Pool::new(config.keep_alive, config.keep_alive_timeout),
retry_canceled_requests: config.retry_canceled_requests,
};

client.schedule_pool_timer();

client
}

fn schedule_pool_timer(&self) {
if let Exec::Handle(ref h) = self.executor {
self.pool.spawn_expired_interval(h);
}
}
}
Expand All @@ -135,6 +117,14 @@ where C: Connect,
/// Send a constructed Request using this Client.
#[inline]
pub fn request(&self, mut req: Request<B>) -> FutureResponse {
// TODO(0.12): do this at construction time.
//
// It cannot be done in the constructor because the Client::configured
// does not have `B: 'static` bounds, which are required to spawn
// the interval. In 0.12, add a static bounds to the constructor,
// and move this.
self.schedule_pool_timer();

match req.version() {
HttpVersion::Http10 |
HttpVersion::Http11 => (),
Expand Down Expand Up @@ -263,6 +253,12 @@ where C: Connect,

Box::new(resp)
}

fn schedule_pool_timer(&self) {
if let Exec::Handle(ref h) = self.executor {
self.pool.spawn_expired_interval(h);
}
}
}

impl<C, B> Service for Client<C, B>
Expand Down
26 changes: 22 additions & 4 deletions src/client/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ struct PoolInner<T> {
// connection.
parked: HashMap<Rc<String>, VecDeque<relay::Sender<Entry<T>>>>,
timeout: Option<Duration>,
// Used to prevent multiple intervals from being spawned to clear
// expired connections.
//
// TODO(0.12): Remove the need for this when Client::schedule_pool_timer
// can be done in Client::new.
expired_timer_spawned: bool,
}

impl<T: Clone + Ready> Pool<T> {
Expand All @@ -51,6 +57,7 @@ impl<T: Clone + Ready> Pool<T> {
idle: HashMap::new(),
parked: HashMap::new(),
timeout: timeout,
expired_timer_spawned: false,
})),
}
}
Expand Down Expand Up @@ -229,12 +236,17 @@ impl<T> Pool<T> {

impl<T: 'static> Pool<T> {
pub(super) fn spawn_expired_interval(&self, handle: &Handle) {
let inner = self.inner.borrow();
let mut inner = self.inner.borrow_mut();

if !inner.enabled {
return;
}

if inner.expired_timer_spawned {
return;
}
inner.expired_timer_spawned = true;

let dur = if let Some(dur) = inner.timeout {
dur
} else {
Expand Down Expand Up @@ -529,7 +541,9 @@ mod tests {

#[test]
fn test_pool_timer_removes_expired() {
let pool = Pool::new(true, Some(Duration::from_secs(1)));
let mut core = ::tokio::reactor::Core::new().unwrap();
let pool = Pool::new(true, Some(Duration::from_millis(100)));
pool.spawn_expired_interval(&core.handle());
let key = Rc::new("foo".to_string());

let mut pooled1 = pool.pooled(key.clone(), 41);
Expand All @@ -540,9 +554,13 @@ mod tests {
pooled3.idle();

assert_eq!(pool.inner.borrow().idle.get(&key).map(|entries| entries.len()), Some(3));
::std::thread::sleep(pool.inner.borrow().timeout.unwrap());

pool.clear_expired();
let timeout = ::tokio::reactor::Timeout::new(
Duration::from_millis(400), // allow for too-good resolution
&core.handle()
).unwrap();
core.run(timeout).unwrap();

assert!(pool.inner.borrow().idle.get(&key).is_none());
}

Expand Down

0 comments on commit 727b747

Please sign in to comment.