Skip to content

Commit 5f36e0e

Browse files
authored
Expose read_timeout from reqwest (#681)
1 parent 0fda34c commit 5f36e0e

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

src/client/mod.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,15 @@ pub enum ClientConfigKey {
185185
/// Supported keys:
186186
/// - `randomize_addresses`
187187
RandomizeAddresses,
188+
/// Read timeout
189+
///
190+
/// The timeout applies to each read operation, and resets after a
191+
/// successful read. This is useful for detecting stalled connections
192+
/// when the size of the response is not known beforehand.
193+
///
194+
/// Supported keys:
195+
/// - `read_timeout`
196+
ReadTimeout,
188197
/// Request timeout
189198
///
190199
/// The timeout is applied from when the request starts connecting until the
@@ -219,6 +228,7 @@ impl AsRef<str> for ClientConfigKey {
219228
Self::ProxyCaCertificate => "proxy_ca_certificate",
220229
Self::ProxyExcludes => "proxy_excludes",
221230
Self::RandomizeAddresses => "randomize_addresses",
231+
Self::ReadTimeout => "read_timeout",
222232
Self::Timeout => "timeout",
223233
Self::UserAgent => "user_agent",
224234
}
@@ -246,6 +256,7 @@ impl FromStr for ClientConfigKey {
246256
"proxy_ca_certificate" => Ok(Self::ProxyCaCertificate),
247257
"proxy_excludes" => Ok(Self::ProxyExcludes),
248258
"randomize_addresses" => Ok(Self::RandomizeAddresses),
259+
"read_timeout" => Ok(Self::ReadTimeout),
249260
"timeout" => Ok(Self::Timeout),
250261
"user_agent" => Ok(Self::UserAgent),
251262
_ => Err(super::Error::UnknownConfigurationKey {
@@ -323,6 +334,7 @@ pub struct ClientOptions {
323334
allow_insecure: ConfigValue<bool>,
324335
timeout: Option<ConfigValue<Duration>>,
325336
connect_timeout: Option<ConfigValue<Duration>>,
337+
read_timeout: Option<ConfigValue<Duration>>,
326338
pool_idle_timeout: Option<ConfigValue<Duration>>,
327339
pool_max_idle_per_host: Option<ConfigValue<usize>>,
328340
http2_keep_alive_interval: Option<ConfigValue<Duration>>,
@@ -357,6 +369,7 @@ impl Default for ClientOptions {
357369
allow_insecure: Default::default(),
358370
timeout: Some(Duration::from_secs(30).into()),
359371
connect_timeout: Some(Duration::from_secs(5).into()),
372+
read_timeout: None,
360373
pool_idle_timeout: None,
361374
pool_max_idle_per_host: None,
362375
http2_keep_alive_interval: None,
@@ -387,6 +400,9 @@ impl ClientOptions {
387400
ClientConfigKey::ConnectTimeout => {
388401
self.connect_timeout = Some(ConfigValue::Deferred(value.into()))
389402
}
403+
ClientConfigKey::ReadTimeout => {
404+
self.read_timeout = Some(ConfigValue::Deferred(value.into()))
405+
}
390406
ClientConfigKey::DefaultContentType => self.default_content_type = Some(value.into()),
391407
ClientConfigKey::Http1Only => self.http1_only.parse(value),
392408
ClientConfigKey::Http2Only => self.http2_only.parse(value),
@@ -428,6 +444,7 @@ impl ClientOptions {
428444
ClientConfigKey::AllowHttp => Some(self.allow_http.to_string()),
429445
ClientConfigKey::AllowInvalidCertificates => Some(self.allow_insecure.to_string()),
430446
ClientConfigKey::ConnectTimeout => self.connect_timeout.as_ref().map(fmt_duration),
447+
ClientConfigKey::ReadTimeout => self.read_timeout.as_ref().map(fmt_duration),
431448
ClientConfigKey::DefaultContentType => self.default_content_type.clone(),
432449
ClientConfigKey::Http1Only => Some(self.http1_only.to_string()),
433450
ClientConfigKey::Http2KeepAliveInterval => {
@@ -652,6 +669,36 @@ impl ClientOptions {
652669
self
653670
}
654671

672+
/// Set a read timeout
673+
///
674+
/// The timeout applies to each read operation, and resets after a
675+
/// successful read. This is useful for detecting stalled connections
676+
/// when the size of the response is not known beforehand.
677+
///
678+
/// Timeout errors are retried, subject to the [`RetryConfig`]
679+
///
680+
/// Default is disabled (no read timeout)
681+
///
682+
/// # See Also
683+
/// * [`Self::with_read_timeout_disabled`] to disable the read timeout
684+
/// * [`Self::with_timeout`] to set a timeout for the overall request
685+
/// * [`Self::with_connect_timeout`] to set a timeout for the connect phase
686+
///
687+
/// [`RetryConfig`]: crate::RetryConfig
688+
pub fn with_read_timeout(mut self, timeout: Duration) -> Self {
689+
self.read_timeout = Some(ConfigValue::Parsed(timeout));
690+
self
691+
}
692+
693+
/// Disables the read timeout
694+
///
695+
/// # See Also
696+
/// * [`Self::with_read_timeout`]
697+
pub fn with_read_timeout_disabled(mut self) -> Self {
698+
self.read_timeout = None;
699+
self
700+
}
701+
655702
/// Set the pool max idle timeout
656703
///
657704
/// This is the length of time an idle connection will be kept alive
@@ -787,6 +834,10 @@ impl ClientOptions {
787834
builder = builder.connect_timeout(timeout.get()?)
788835
}
789836

837+
if let Some(timeout) = &self.read_timeout {
838+
builder = builder.read_timeout(timeout.get()?)
839+
}
840+
790841
if let Some(timeout) = &self.pool_idle_timeout {
791842
builder = builder.pool_idle_timeout(timeout.get()?)
792843
}
@@ -1019,6 +1070,7 @@ mod tests {
10191070
let pool_idle_timeout = "93 seconds".to_string();
10201071
let pool_max_idle_per_host = "94".to_string();
10211072
let proxy_url = "https://fake_proxy_url".to_string();
1073+
let read_timeout = "45 seconds".to_string();
10221074
let timeout = "95 seconds".to_string();
10231075
let user_agent = "object_store:fake_user_agent".to_string();
10241076

@@ -1045,6 +1097,7 @@ mod tests {
10451097
("pool_idle_timeout", pool_idle_timeout.clone()),
10461098
("pool_max_idle_per_host", pool_max_idle_per_host.clone()),
10471099
("proxy_url", proxy_url.clone()),
1100+
("read_timeout", read_timeout.clone()),
10481101
("timeout", timeout.clone()),
10491102
("user_agent", user_agent.clone()),
10501103
]);
@@ -1134,6 +1187,12 @@ mod tests {
11341187
.unwrap(),
11351188
proxy_url
11361189
);
1190+
assert_eq!(
1191+
builder
1192+
.get_config_value(&ClientConfigKey::ReadTimeout)
1193+
.unwrap(),
1194+
read_timeout
1195+
);
11371196
assert_eq!(
11381197
builder.get_config_value(&ClientConfigKey::Timeout).unwrap(),
11391198
timeout

0 commit comments

Comments
 (0)