From d743376514d121ae2fdfd8a3f64ebc6083183ac5 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Thu, 26 Dec 2024 13:12:59 +0100 Subject: [PATCH] feat(client): allow to set response timeout per request --- client/src/middleware/redirect.rs | 17 ++++++++++++++-- client/src/request.rs | 32 ++++++++++++++++++++----------- client/src/service/http.rs | 23 +++++++++++----------- client/src/service/mod.rs | 12 ++++++++---- 4 files changed, 56 insertions(+), 28 deletions(-) diff --git a/client/src/middleware/redirect.rs b/client/src/middleware/redirect.rs index ab2df6eb5..606785332 100644 --- a/client/src/middleware/redirect.rs +++ b/client/src/middleware/redirect.rs @@ -49,7 +49,12 @@ where type Error = Error; async fn call(&self, req: ServiceRequest<'r, 'c>) -> Result { - let ServiceRequest { req, client, timeout } = req; + let ServiceRequest { + req, + client, + request_timeout, + response_timeout, + } = req; let mut headers = req.headers().clone(); let mut method = req.method().clone(); let mut uri = req.uri().clone(); @@ -57,7 +62,15 @@ where let mut count = 0; loop { - let mut res = self.service.call(ServiceRequest { req, client, timeout }).await?; + let mut res = self + .service + .call(ServiceRequest { + req, + client, + request_timeout, + response_timeout, + }) + .await?; if count == MAX { return Ok(res); diff --git a/client/src/request.rs b/client/src/request.rs index 44b95e64b..8e64b03d1 100644 --- a/client/src/request.rs +++ b/client/src/request.rs @@ -20,7 +20,8 @@ pub struct RequestBuilder<'a, M = marker::Http> { pub(crate) req: http::Request, pub(crate) err: Vec, client: &'a Client, - timeout: Duration, + request_timeout: Duration, + response_timeout: Duration, _marker: PhantomData, } @@ -102,7 +103,8 @@ impl<'a, M> RequestBuilder<'a, M> { req: req.map(BoxBody::new), err: Vec::new(), client, - timeout: client.timeout_config.request_timeout, + request_timeout: client.timeout_config.request_timeout, + response_timeout: client.timeout_config.response_timeout, _marker: PhantomData, } } @@ -112,7 +114,8 @@ impl<'a, M> RequestBuilder<'a, M> { req: self.req, err: self.err, client: self.client, - timeout: self.timeout, + request_timeout: self.request_timeout, + response_timeout: self.response_timeout, _marker: PhantomData, } } @@ -123,7 +126,8 @@ impl<'a, M> RequestBuilder<'a, M> { mut req, err, client, - timeout, + request_timeout, + response_timeout, .. } = self; @@ -136,7 +140,8 @@ impl<'a, M> RequestBuilder<'a, M> { .call(ServiceRequest { req: &mut req, client, - timeout, + request_timeout, + response_timeout, }) .await } @@ -198,14 +203,19 @@ impl<'a, M> RequestBuilder<'a, M> { self } - /// Set timeout of this request. + /// Set timeout for request. /// - /// The value passed would override global [ClientBuilder::set_request_timeout]. + /// Default to client's [TimeoutConfig::request_timeout]. + pub fn set_request_timeout(mut self, dur: Duration) -> Self { + self.request_timeout = dur; + self + } + + /// Set timeout for collecting response body. /// - /// [ClientBuilder::set_request_timeout]: crate::builder::ClientBuilder::set_request_timeout - #[inline] - pub fn timeout(mut self, dur: Duration) -> Self { - self.timeout = dur; + /// Default to client's [TimeoutConfig::response_timeout]. + pub fn set_response_timeout(mut self, dur: Duration) -> Self { + self.response_timeout = dur; self } diff --git a/client/src/service/http.rs b/client/src/service/http.rs index 725cbd28b..2e662a1ac 100644 --- a/client/src/service/http.rs +++ b/client/src/service/http.rs @@ -24,7 +24,12 @@ pub(crate) fn base_service() -> HttpService { #[cfg(any(feature = "http1", feature = "http2", feature = "http3"))] use crate::{error::TimeoutError, timeout::Timeout}; - let ServiceRequest { req, client, timeout } = req; + let ServiceRequest { + req, + client, + request_timeout, + response_timeout, + } = req; let uri = Uri::try_parse(req.uri())?; @@ -41,7 +46,7 @@ pub(crate) fn base_service() -> HttpService { match version { Version::HTTP_2 | Version::HTTP_3 => match client.shared_pool.acquire(&connect.uri).await { shared::AcquireOutput::Conn(mut _conn) => { - let mut _timer = Box::pin(tokio::time::sleep(timeout)); + let mut _timer = Box::pin(tokio::time::sleep(request_timeout)); *req.version_mut() = version; #[allow(unreachable_code)] return match _conn.conn { @@ -51,10 +56,7 @@ pub(crate) fn base_service() -> HttpService { .timeout(_timer.as_mut()) .await { - Ok(Ok(res)) => { - let timeout = client.timeout_config.response_timeout; - Ok(Response::new(res, _timer, timeout)) - } + Ok(Ok(res)) => Ok(Response::new(res, _timer, response_timeout)), Ok(Err(e)) => { _conn.destroy_on_drop(); Err(e.into()) @@ -72,8 +74,7 @@ pub(crate) fn base_service() -> HttpService { .await .map_err(|_| TimeoutError::Request)??; - let timeout = client.timeout_config.response_timeout; - Ok(Response::new(res, _timer, timeout)) + Ok(Response::new(res, _timer, response_timeout)) } }; } @@ -157,7 +158,7 @@ pub(crate) fn base_service() -> HttpService { #[cfg(feature = "http1")] { - let mut timer = Box::pin(tokio::time::sleep(timeout)); + let mut timer = Box::pin(tokio::time::sleep(request_timeout)); let res = crate::h1::proto::send(&mut *_conn, _date, req) .timeout(timer.as_mut()) .await; @@ -169,8 +170,8 @@ pub(crate) fn base_service() -> HttpService { } let body = crate::h1::body::ResponseBody::new(_conn, buf, decoder); let res = res.map(|_| crate::body::ResponseBody::H1(body)); - let timeout = client.timeout_config.response_timeout; - Ok(Response::new(res, timer, timeout)) + + Ok(Response::new(res, timer, response_timeout)) } Ok(Err(e)) => { _conn.destroy_on_drop(); diff --git a/client/src/service/mod.rs b/client/src/service/mod.rs index 0ab3a46a1..bc6b92577 100644 --- a/client/src/service/mod.rs +++ b/client/src/service/mod.rs @@ -68,7 +68,8 @@ where pub struct ServiceRequest<'r, 'c> { pub req: &'r mut Request, pub client: &'c Client, - pub timeout: Duration, + pub request_timeout: Duration, + pub response_timeout: Duration, } #[cfg(test)] @@ -114,7 +115,8 @@ mod test { ServiceRequest { req, client: &self.0, - timeout: self.0.timeout_config.request_timeout, + request_timeout: self.0.timeout_config.request_timeout, + response_timeout: self.0.timeout_config.response_timeout, } } } @@ -125,7 +127,9 @@ mod test { async fn call( &self, - ServiceRequest { req, timeout, .. }: ServiceRequest<'r, 'c>, + ServiceRequest { + req, response_timeout, .. + }: ServiceRequest<'r, 'c>, ) -> Result { let handler = req.extensions().get::().unwrap().clone(); @@ -134,7 +138,7 @@ mod test { Ok(Response::new( res, Box::pin(tokio::time::sleep(Duration::from_secs(0))), - timeout, + response_timeout, )) } }