fix(client): properly close idle connections after timeout
Additionally fixes if there were idle connections when a `Client` is dropped. Only fixes with the no-proto dispatcher, as changing internals for the tokio-proto dispatcher would be much harder, and it will replace it very soon. Closes #1397
This commit is contained in:
		| @@ -249,8 +249,12 @@ where C: Connect, | ||||
|                     let pool_key = Rc::new(domain.to_string()); | ||||
|                     self.connector.connect(url) | ||||
|                         .map(move |io| { | ||||
|                             let (tx, rx) = mpsc::channel(1); | ||||
|                             let pooled = pool.pooled(pool_key, RefCell::new(tx)); | ||||
|                             let (tx, rx) = mpsc::channel(0); | ||||
|                             let tx = HyperClient { | ||||
|                                 tx: RefCell::new(tx), | ||||
|                                 should_close: true, | ||||
|                             }; | ||||
|                             let pooled = pool.pooled(pool_key, tx); | ||||
|                             let conn = proto::Conn::<_, _, proto::ClientTransaction, _>::new(io, pooled.clone()); | ||||
|                             let dispatch = proto::dispatch::Dispatcher::new(proto::dispatch::Client::new(rx), conn); | ||||
|                             handle.spawn(dispatch.map_err(|err| error!("no_proto error: {}", err))); | ||||
| @@ -269,9 +273,10 @@ where C: Connect, | ||||
|                         e.into() | ||||
|                     }); | ||||
|  | ||||
|                 let resp = race.and_then(move |client| { | ||||
|                 let resp = race.and_then(move |mut client| { | ||||
|                     let (callback, rx) = oneshot::channel(); | ||||
|                     client.borrow_mut().start_send((head, body, callback)).unwrap(); | ||||
|                     client.tx.borrow_mut().start_send(proto::dispatch::ClientMsg::Request(head, body, callback)).unwrap(); | ||||
|                     client.should_close = false; | ||||
|                     rx.then(|res| { | ||||
|                         match res { | ||||
|                             Ok(Ok(res)) => Ok(res), | ||||
| @@ -309,7 +314,29 @@ impl<C, B> fmt::Debug for Client<C, B> { | ||||
| } | ||||
|  | ||||
| type ProtoClient<B> = ClientProxy<Message<RequestHead, B>, Message<proto::ResponseHead, TokioBody>, ::Error>; | ||||
| type HyperClient<B> = RefCell<::futures::sync::mpsc::Sender<(RequestHead, Option<B>, ::futures::sync::oneshot::Sender<::Result<::Response>>)>>; | ||||
|  | ||||
| struct HyperClient<B> { | ||||
|     tx: RefCell<::futures::sync::mpsc::Sender<proto::dispatch::ClientMsg<B>>>, | ||||
|     should_close: bool, | ||||
| } | ||||
|  | ||||
| impl<B> Clone for HyperClient<B> { | ||||
|     fn clone(&self) -> HyperClient<B> { | ||||
|         HyperClient { | ||||
|             tx: self.tx.clone(), | ||||
|             should_close: self.should_close, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<B> Drop for HyperClient<B> { | ||||
|     fn drop(&mut self) { | ||||
|         if self.should_close { | ||||
|             self.should_close = false; | ||||
|             let _ = self.tx.borrow_mut().try_send(proto::dispatch::ClientMsg::Close); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| enum Dispatch<B> { | ||||
|     Proto(Pool<ProtoClient<B>>), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user