This is an automated email from the ASF dual-hosted git repository.

tustvold pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/master by this push:
     new 31bc84c91e Default connection and request timeouts of 5 seconds (#4928)
31bc84c91e is described below

commit 31bc84c91e7d6c509443f6e73bda0df32a0a5cba
Author: Raphael Taylor-Davies <[email protected]>
AuthorDate: Mon Oct 16 10:56:25 2023 +0100

    Default connection and request timeouts of 5 seconds (#4928)
    
    * Default connection and request timeouts of 5 seconds
    
    * Clippy
    
    * Allow disabling timeouts
---
 object_store/src/aws/mod.rs    |  3 +-
 object_store/src/azure/mod.rs  |  2 +-
 object_store/src/client/mod.rs | 66 ++++++++++++++++++++++++++++++++++++++++--
 object_store/src/gcp/mod.rs    |  2 +-
 4 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/object_store/src/aws/mod.rs b/object_store/src/aws/mod.rs
index 70170a3cf4..3ddce08002 100644
--- a/object_store/src/aws/mod.rs
+++ b/object_store/src/aws/mod.rs
@@ -1130,8 +1130,7 @@ impl AmazonS3Builder {
 
             Arc::new(TokenCredentialProvider::new(
                 token,
-                // The instance metadata endpoint is access over HTTP
-                self.client_options.clone().with_allow_http(true).client()?,
+                self.client_options.metadata_client()?,
                 self.retry_config.clone(),
             )) as _
         };
diff --git a/object_store/src/azure/mod.rs b/object_store/src/azure/mod.rs
index 9017634c42..190b73bf94 100644
--- a/object_store/src/azure/mod.rs
+++ b/object_store/src/azure/mod.rs
@@ -1070,7 +1070,7 @@ impl MicrosoftAzureBuilder {
                 );
                 Arc::new(TokenCredentialProvider::new(
                     msi_credential,
-                    
self.client_options.clone().with_allow_http(true).client()?,
+                    self.client_options.metadata_client()?,
                     self.retry_config.clone(),
                 )) as _
             };
diff --git a/object_store/src/client/mod.rs b/object_store/src/client/mod.rs
index ee9d62a44f..137da2b375 100644
--- a/object_store/src/client/mod.rs
+++ b/object_store/src/client/mod.rs
@@ -166,7 +166,7 @@ impl FromStr for ClientConfigKey {
 }
 
 /// HTTP client configuration for remote object stores
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
 pub struct ClientOptions {
     user_agent: Option<ConfigValue<HeaderValue>>,
     content_type_map: HashMap<String, String>,
@@ -188,6 +188,35 @@ pub struct ClientOptions {
     http2_only: ConfigValue<bool>,
 }
 
+impl Default for ClientOptions {
+    fn default() -> Self {
+        // Defaults based on
+        // 
<https://docs.aws.amazon.com/sdkref/latest/guide/feature-smart-config-defaults.html>
+        // 
<https://docs.aws.amazon.com/whitepapers/latest/s3-optimizing-performance-best-practices/timeouts-and-retries-for-latency-sensitive-applications.html>
+        // Which recommend a connection timeout of 3.1s and a request timeout 
of 2s
+        Self {
+            user_agent: None,
+            content_type_map: Default::default(),
+            default_content_type: None,
+            default_headers: None,
+            proxy_url: None,
+            proxy_ca_certificate: None,
+            proxy_excludes: None,
+            allow_http: Default::default(),
+            allow_insecure: Default::default(),
+            timeout: Some(Duration::from_secs(5).into()),
+            connect_timeout: Some(Duration::from_secs(5).into()),
+            pool_idle_timeout: None,
+            pool_max_idle_per_host: None,
+            http2_keep_alive_interval: None,
+            http2_keep_alive_timeout: None,
+            http2_keep_alive_while_idle: Default::default(),
+            http1_only: Default::default(),
+            http2_only: Default::default(),
+        }
+    }
+}
+
 impl ClientOptions {
     /// Create a new [`ClientOptions`] with default values
     pub fn new() -> Self {
@@ -367,17 +396,37 @@ impl ClientOptions {
     ///
     /// The timeout is applied from when the request starts connecting until 
the
     /// response body has finished
+    ///
+    /// Default is 5 seconds
     pub fn with_timeout(mut self, timeout: Duration) -> Self {
         self.timeout = Some(ConfigValue::Parsed(timeout));
         self
     }
 
+    /// Disables the request timeout
+    ///
+    /// See [`Self::with_timeout`]
+    pub fn with_timeout_disabled(mut self) -> Self {
+        self.timeout = None;
+        self
+    }
+
     /// Set a timeout for only the connect phase of a Client
+    ///
+    /// Default is 5 seconds
     pub fn with_connect_timeout(mut self, timeout: Duration) -> Self {
         self.connect_timeout = Some(ConfigValue::Parsed(timeout));
         self
     }
 
+    /// Disables the connection timeout
+    ///
+    /// See [`Self::with_connect_timeout`]
+    pub fn with_connect_timeout_disabled(mut self) -> Self {
+        self.timeout = None;
+        self
+    }
+
     /// Set the pool max idle timeout
     ///
     /// This is the length of time an idle connection will be kept alive
@@ -444,7 +493,20 @@ impl ClientOptions {
         }
     }
 
-    pub(crate) fn client(&self) -> super::Result<Client> {
+    /// Create a [`Client`] with overrides optimised for metadata endpoint 
access
+    ///
+    /// In particular:
+    /// * Allows HTTP as metadata endpoints do not use TLS
+    /// * Configures a low connection timeout to provide quick feedback if not 
present
+    #[cfg(any(feature = "aws", feature = "gcp", feature = "azure"))]
+    pub(crate) fn metadata_client(&self) -> Result<Client> {
+        self.clone()
+            .with_allow_http(true)
+            .with_connect_timeout(Duration::from_secs(1))
+            .client()
+    }
+
+    pub(crate) fn client(&self) -> Result<Client> {
         let mut builder = ClientBuilder::new();
 
         match &self.user_agent {
diff --git a/object_store/src/gcp/mod.rs b/object_store/src/gcp/mod.rs
index f80704b917..f8a16310dd 100644
--- a/object_store/src/gcp/mod.rs
+++ b/object_store/src/gcp/mod.rs
@@ -1071,7 +1071,7 @@ impl GoogleCloudStorageBuilder {
         } else {
             Arc::new(TokenCredentialProvider::new(
                 InstanceCredentialProvider::new(audience),
-                self.client_options.clone().with_allow_http(true).client()?,
+                self.client_options.metadata_client()?,
                 self.retry_config.clone(),
             )) as _
         };

Reply via email to