diff --git a/.changeset/http-timeouts.md b/.changeset/http-timeouts.md new file mode 100644 index 00000000..2ca5a156 --- /dev/null +++ b/.changeset/http-timeouts.md @@ -0,0 +1 @@ +---\n"@googleworkspace/cli": patch\n---\n\nfix(client): add 10s connect timeout to prevent hangs on initial connection diff --git a/src/client.rs b/src/client.rs index e0abe409..de94fd4b 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,5 +1,12 @@ use reqwest::header::{HeaderMap, HeaderValue}; +const MAX_RETRIES: u32 = 3; +/// Maximum seconds to sleep on a 429 Retry-After header. Prevents a hostile +/// or misconfigured server from hanging the process indefinitely. +const MAX_RETRY_DELAY_SECS: u64 = 60; +const CONNECT_TIMEOUT_SECS: u64 = 10; +const REQUEST_TIMEOUT_SECS: u64 = 600; + pub fn build_client() -> Result { let mut headers = HeaderMap::new(); let name = env!("CARGO_PKG_NAME"); @@ -13,17 +20,14 @@ pub fn build_client() -> Result { reqwest::Client::builder() .default_headers(headers) + .connect_timeout(std::time::Duration::from_secs(CONNECT_TIMEOUT_SECS)) + .timeout(std::time::Duration::from_secs(REQUEST_TIMEOUT_SECS)) .build() .map_err(|e| { crate::error::GwsError::Other(anyhow::anyhow!("Failed to build HTTP client: {e}")) }) } -const MAX_RETRIES: u32 = 3; -/// Maximum seconds to sleep on a 429 Retry-After header. Prevents a hostile -/// or misconfigured server from hanging the process indefinitely. -const MAX_RETRY_DELAY_SECS: u64 = 60; - /// Send an HTTP request with automatic retry on 429 (rate limit) responses. /// Respects the `Retry-After` header; falls back to exponential backoff (1s, 2s, 4s). pub async fn send_with_retry(