From a0afefb0433b7dd4c0fcab3b68672df18742c2c2 Mon Sep 17 00:00:00 2001 From: Victor Oladimeji Date: Sun, 7 Jun 2026 12:53:32 +0100 Subject: [PATCH] fix: add 30s timeouts to all HTTP clients Every reqwest client was built with Client::new(), which has no request timeout, so a slow/unresponsive RPC node, Brevo, Groq, or Google endpoint would hold a task/connection open indefinitely (server resource exhaustion; the CLI appears to freeze). Build clients with a 30s timeout, falling back to the default client if the builder ever fails. Covers backend services (sui, ai, email), the Google OAuth client, the CLI login client, and all five chain adapters (sui, ethereum, solana, aptos, soroban). Closes #36 --- backend/api/src/api/handlers/auth_handler.rs | 5 ++++- backend/api/src/services/ai_service.rs | 5 ++++- backend/api/src/services/email_service.rs | 5 ++++- backend/api/src/services/sui_service.rs | 5 ++++- cli/src/chains/aptos.rs | 5 ++++- cli/src/chains/ethereum.rs | 5 ++++- cli/src/chains/solana.rs | 5 ++++- cli/src/chains/soroban.rs | 5 ++++- cli/src/chains/sui.rs | 5 ++++- cli/src/cli/handlers.rs | 5 ++++- 10 files changed, 40 insertions(+), 10 deletions(-) diff --git a/backend/api/src/api/handlers/auth_handler.rs b/backend/api/src/api/handlers/auth_handler.rs index 1fb7e65..f04eca4 100644 --- a/backend/api/src/api/handlers/auth_handler.rs +++ b/backend/api/src/api/handlers/auth_handler.rs @@ -224,7 +224,10 @@ pub async fn google_callback( let frontend_url = std::env::var("FRONTEND_URL").unwrap_or_else(|_| "http://localhost:3000".to_string()); - let client = reqwest::Client::new(); + let client = reqwest::Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| reqwest::Client::new()); let token_res = client .post("https://oauth2.googleapis.com/token") .form(&[ diff --git a/backend/api/src/services/ai_service.rs b/backend/api/src/services/ai_service.rs index 2b686ea..1c1ec51 100644 --- a/backend/api/src/services/ai_service.rs +++ b/backend/api/src/services/ai_service.rs @@ -63,7 +63,10 @@ impl AiService { let model = resolve_model(); Self { - client: Client::new(), + client: Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| Client::new()), api_keys: Arc::new(api_keys), model, next_key_index: Arc::new(AtomicUsize::new(0)), diff --git a/backend/api/src/services/email_service.rs b/backend/api/src/services/email_service.rs index 4959b46..ebe9da5 100644 --- a/backend/api/src/services/email_service.rs +++ b/backend/api/src/services/email_service.rs @@ -12,7 +12,10 @@ impl EmailService { pub fn new(api_key: String) -> Self { Self { api_key, - client: Client::new(), + client: Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| Client::new()), } } diff --git a/backend/api/src/services/sui_service.rs b/backend/api/src/services/sui_service.rs index 2f5647d..a1599cb 100644 --- a/backend/api/src/services/sui_service.rs +++ b/backend/api/src/services/sui_service.rs @@ -33,7 +33,10 @@ impl SuiService { pub fn new(rpc_repo: RpcRepository, _rpc_url: String) -> Self { Self { rpc_repo, - client: Client::new(), + client: Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| Client::new()), } } diff --git a/cli/src/chains/aptos.rs b/cli/src/chains/aptos.rs index 2244d5a..54bd8f5 100644 --- a/cli/src/chains/aptos.rs +++ b/cli/src/chains/aptos.rs @@ -24,7 +24,10 @@ impl AptosAdapter { }); Self { - client: Client::new(), + client: Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| Client::new()), rpc_url: url, } } diff --git a/cli/src/chains/ethereum.rs b/cli/src/chains/ethereum.rs index 1d57793..bb3ff8d 100644 --- a/cli/src/chains/ethereum.rs +++ b/cli/src/chains/ethereum.rs @@ -24,7 +24,10 @@ impl EthereumAdapter { }); Self { - client: Client::new(), + client: Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| Client::new()), rpc_url: url, } } diff --git a/cli/src/chains/solana.rs b/cli/src/chains/solana.rs index a1ca0c5..19625bd 100644 --- a/cli/src/chains/solana.rs +++ b/cli/src/chains/solana.rs @@ -24,7 +24,10 @@ impl SolanaAdapter { }); Self { - client: Client::new(), + client: Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| Client::new()), rpc_url: url, } } diff --git a/cli/src/chains/soroban.rs b/cli/src/chains/soroban.rs index 092dc0a..9da8085 100644 --- a/cli/src/chains/soroban.rs +++ b/cli/src/chains/soroban.rs @@ -32,7 +32,10 @@ impl SorobanAdapter { }); Self { - client: Client::new(), + client: Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| Client::new()), rpc_url: url, } } diff --git a/cli/src/chains/sui.rs b/cli/src/chains/sui.rs index a41898f..dcd5adb 100644 --- a/cli/src/chains/sui.rs +++ b/cli/src/chains/sui.rs @@ -25,7 +25,10 @@ impl SuiAdapter { }); Self { - client: Client::new(), + client: Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| Client::new()), rpc_url: url, } } diff --git a/cli/src/cli/handlers.rs b/cli/src/cli/handlers.rs index 8ed465e..4cadd44 100644 --- a/cli/src/cli/handlers.rs +++ b/cli/src/cli/handlers.rs @@ -274,7 +274,10 @@ impl CommandHandler { password, }; - let client = reqwest::Client::new(); + let client = reqwest::Client::builder() + .timeout(std::time::Duration::from_secs(30)) + .build() + .unwrap_or_else(|_| reqwest::Client::new()); let api_url = std::env::var("API_URL").unwrap_or_else(|_| "http://localhost:8000".to_string());