From ca43ad1d00db68bf550de0e7637bdd2cf3aa3fa1 Mon Sep 17 00:00:00 2001 From: Jon Seager Date: Fri, 6 Feb 2026 18:19:37 +0000 Subject: [PATCH] fix: set HTTP client timeout and remove pagination double-fetch - Set a 30-second default timeout on the shared reqwest client so future call sites can't hang indefinitely. - Use ensure_page_within() to clamp the page before querying instead of fetching, detecting an empty result, and re-fetching. --- src/application/state.rs | 6 ++++- src/infrastructure/repositories/pagination.rs | 24 +++++-------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/application/state.rs b/src/application/state.rs index db4864c..222bcd0 100644 --- a/src/application/state.rs +++ b/src/application/state.rs @@ -138,7 +138,11 @@ impl AppState { ai_usage_repo, webauthn: config.webauthn, challenge_store: Arc::new(ChallengeStore::new()), - http_client: reqwest::Client::new(), + #[allow(clippy::expect_used)] + http_client: reqwest::ClientBuilder::new() + .timeout(std::time::Duration::from_secs(30)) + .build() + .expect("failed to build HTTP client"), foursquare_url: config.foursquare_url, foursquare_api_key: config.foursquare_api_key, openrouter_url: config.openrouter_url, diff --git a/src/infrastructure/repositories/pagination.rs b/src/infrastructure/repositories/pagination.rs index 9d87c17..a2a9b61 100644 --- a/src/infrastructure/repositories/pagination.rs +++ b/src/infrastructure/repositories/pagination.rs @@ -54,12 +54,14 @@ where } PageSize::Limited(page_size) => { let limit = i64::from(page_size); - let mut page = request.page(); - let offset = i64::from(page - 1).saturating_mul(limit); - let total = fetch_count(pool, count_query, search).await?; - let mut records = fetch_records::( + // Clamp page to valid range before fetching + let adjusted = (*request).ensure_page_within(total as u64); + let page = adjusted.page(); + let offset = i64::from(page - 1).saturating_mul(limit); + + let records = fetch_records::( pool, base_query, order_clause, @@ -68,20 +70,6 @@ where ) .await?; - if page > 1 && records.is_empty() && total > 0 { - let last_page = ((total + limit - 1) / limit) as u32; - page = last_page.max(1); - let offset = i64::from(page - 1).saturating_mul(limit); - records = fetch_records::( - pool, - base_query, - order_clause, - search, - Some((limit, offset)), - ) - .await?; - } - let mut items = Vec::with_capacity(records.len()); for record in records { items.push(map_fn(record)?);