feat(client): Client will retry requests on fresh connections
If a request sees an error on a pooled connection before ever writing any bytes, it will now retry with a new connection. This can be configured with `Config::retry_canceled_requests(bool)`.
This commit is contained in:
		| @@ -32,7 +32,7 @@ pub struct Server<S: Service> { | ||||
| } | ||||
|  | ||||
| pub struct Client<B> { | ||||
|     callback: Option<oneshot::Sender<::Result<::Response>>>, | ||||
|     callback: Option<oneshot::Sender<Result<::Response, (::Error, Option<ClientMsg<B>>)>>>, | ||||
|     rx: ClientRx<B>, | ||||
| } | ||||
|  | ||||
| @@ -398,12 +398,13 @@ where | ||||
|             }, | ||||
|             Err(err) => { | ||||
|                 if let Some(cb) = self.callback.take() { | ||||
|                     let _ = cb.send(Err(err)); | ||||
|                     let _ = cb.send(Err((err, None))); | ||||
|                     Ok(()) | ||||
|                 } else if let Ok(Async::Ready(Some((_, cb)))) = self.rx.poll() { | ||||
|                 } else if let Ok(Async::Ready(Some((req, cb)))) = self.rx.poll() { | ||||
|                     trace!("canceling queued request with connection error: {}", err); | ||||
|                     // in this case, the message was never even started, so it's safe to tell | ||||
|                     // the user that the request was completely canceled | ||||
|                     let _ = cb.send(Err(::Error::new_canceled(Some(err)))); | ||||
|                     let _ = cb.send(Err((::Error::new_canceled(Some(err)), Some(req)))); | ||||
|                     Ok(()) | ||||
|                 } else { | ||||
|                     Err(err) | ||||
|   | ||||
| @@ -105,6 +105,8 @@ impl<B> Request<B> { | ||||
|     /// protected by TLS. | ||||
|     #[inline] | ||||
|     pub fn set_proxy(&mut self, is_proxy: bool) { self.is_proxy = is_proxy; } | ||||
|  | ||||
|     pub(crate) fn is_proxy(&self) -> bool { self.is_proxy } | ||||
| } | ||||
|  | ||||
| impl Request<Body> { | ||||
| @@ -165,16 +167,9 @@ impl<B> From<http::Request<B>> for Request<B> { | ||||
|  | ||||
| /// Constructs a request using a received ResponseHead and optional body | ||||
| pub fn from_wire(addr: Option<SocketAddr>, incoming: RequestHead, body: Option<Body>) -> Request<Body> { | ||||
|     let MessageHead { version, subject: RequestLine(method, uri), headers } = incoming; | ||||
|  | ||||
|     Request { | ||||
|         method: method, | ||||
|         uri: uri, | ||||
|         headers: headers, | ||||
|         version: version, | ||||
|         remote_addr: addr, | ||||
|         body: body, | ||||
|         is_proxy: false, | ||||
|         ..join((incoming, body)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -192,6 +187,20 @@ pub fn split<B>(req: Request<B>) -> (RequestHead, Option<B>) { | ||||
|     (head, req.body) | ||||
| } | ||||
|  | ||||
| pub fn join<B>((head, body): (RequestHead, Option<B>)) -> Request<B> { | ||||
|     let MessageHead { version, subject: RequestLine(method, uri), headers } = head; | ||||
|  | ||||
|     Request { | ||||
|         method: method, | ||||
|         uri: uri, | ||||
|         headers: headers, | ||||
|         version: version, | ||||
|         remote_addr: None, | ||||
|         body: body, | ||||
|         is_proxy: false, | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub fn addr<B>(req: &mut Request<B>, addr: SocketAddr) { | ||||
|     req.remote_addr = Some(addr); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user