diff --git a/pcrDev.json b/pcrDev.json index 2786403..7548cc7 100644 --- a/pcrDev.json +++ b/pcrDev.json @@ -1,6 +1,6 @@ { "HashAlgorithm": "Sha384 { ... }", - "PCR0": "6b15f0571de13a6357e646bbe3772a8fe32fdd85b07ba97b3a6f95bdc43023dd9deb5710c26b75346de90157d9ecdd1f", + "PCR0": "463a0bbbfc59a20453b42bde1f5b0c3f956f4c07741d93cda06c4826436106f343b4507ccc65c04078246de9013af2da", "PCR1": "e45de6f4e9809176f6adc68df999f87f32a602361247d5819d1edf11ac5a403cfbb609943705844251af85713a17c83a", - "PCR2": "cb114b8e27fb08576dee6a0481eef5ad96030a4a6402e7783ff363abbc5d72a2d916d053706cb76c6ff405ded55b77ae" + "PCR2": "8ef81c34e9c4b8c09e44456a78d97bffd20fe241d76bcac9daece530de9867f9d9462e8883fea6bb419e00a8d77550f1" } diff --git a/pcrProd.json b/pcrProd.json index c262525..606b00a 100644 --- a/pcrProd.json +++ b/pcrProd.json @@ -1,6 +1,6 @@ { "HashAlgorithm": "Sha384 { ... }", - "PCR0": "02a41da2df084fd1dee420d7717bef6dc0120f1d6a0b7fded3f4c7a539be4044b3061c71bc7156731db1fb66494097b0", + "PCR0": "2f88308190976b07464ea6e10ecd6675200b07974b5f345eeccad12a4703bb5f67a4ab3cb6ad419c6ed9b93c62e9caa5", "PCR1": "e45de6f4e9809176f6adc68df999f87f32a602361247d5819d1edf11ac5a403cfbb609943705844251af85713a17c83a", - "PCR2": "4563722b974255c127d3706805645d13d10a4f01fe8e4e242e58cf1c89c21d27fbbb8a3be197c649e8dc5694370f3c12" + "PCR2": "6a6b330f35bfe8623eebd256e1e3f80b414354071485ec9f9f8e1551dafb1cb7fa991233d01c07af52141a9b97b90469" } diff --git a/src/web/openai.rs b/src/web/openai.rs index fb5bbf0..01b0c1c 100644 --- a/src/web/openai.rs +++ b/src/web/openai.rs @@ -98,10 +98,15 @@ async fn proxy_openai( }; let openai_api_base = &state.openai_api_base; - // Create a new hyper client + // Create a new hyper client with extended timeouts let https = HttpsConnector::new(); let client = Client::builder() - .pool_idle_timeout(Duration::from_secs(15)) + .pool_idle_timeout(Duration::from_secs(60)) // Increased from 15 to 60 seconds + .pool_max_idle_per_host(32) // Increased connection pool size + .http2_keep_alive_interval(Some(Duration::from_secs(20))) // Keep connections alive + .http2_keep_alive_timeout(Duration::from_secs(10)) // Timeout for keep-alive pings + .http1_read_buf_exact_size(65_536) // Increased buffer size + .http1_title_case_headers(true) // Improved compatibility .build::<_, Body>(https); // Prepare the request to OpenAI @@ -137,11 +142,73 @@ async fn proxy_openai( })?; debug!("Sending request to OpenAI"); - // Send the request to OpenAI - let res = client.request(req).await.map_err(|e| { - error!("Failed to send request to OpenAI: {:?}", e); - ApiError::InternalServerError - })?; + // Send the request to OpenAI with retry logic + let mut attempts = 0; + let max_attempts = 3; + let mut _last_error = None; + + // We need to manually clone the request since hyper::Request doesn't have try_clone + // Extract the components we need for retrying + let (parts, body) = req.into_parts(); + let method = parts.method.clone(); + let uri = parts.uri.clone(); + let headers = parts.headers.clone(); + let version = parts.version; + + // Convert body to bytes so we can reuse it + let body_bytes = match hyper::body::to_bytes(body).await { + Ok(bytes) => bytes, + Err(e) => { + error!("Failed to read request body: {:?}", e); + return Err(ApiError::InternalServerError); + } + }; + + let res = loop { + attempts += 1; + + // Rebuild the request from the saved components + let mut req_builder = hyper::Request::builder() + .method(method.clone()) + .uri(uri.clone()) + .version(version); + + // Add all headers + for (name, value) in headers.iter() { + req_builder = req_builder.header(name, value); + } + + // Build the request with the body + let request = req_builder + .body(hyper::Body::from(body_bytes.clone())) + .map_err(|e| { + error!("Failed to build request: {:?}", e); + ApiError::InternalServerError + })?; + + match client.request(request).await { + Ok(response) => break response, + Err(e) => { + error!( + "Attempt {}/{}: Failed to send request to OpenAI: {:?}", + attempts, max_attempts, e + ); + _last_error = Some(e); + + // If we've reached max attempts, return the error + if attempts >= max_attempts { + error!("Max retry attempts reached. Giving up."); + return Err(ApiError::InternalServerError); + } + + // Wait before retrying (exponential backoff with max delay cap of 3 seconds) + let backoff_ms = 500 * 2_u64.pow(attempts as u32 - 1); + let capped_backoff_ms = std::cmp::min(backoff_ms, 3000); // Cap at 3 seconds + let delay = std::time::Duration::from_millis(capped_backoff_ms); + tokio::time::sleep(delay).await; + } + } + }; // Check if the response is successful if !res.status().is_success() { @@ -201,12 +268,18 @@ async fn proxy_openai( processed_events } Err(e) => { + // Log the error with more details to help debug error!( "Error reading response body: {:?}. Current buffer: {}", e, buffer.lock().unwrap() ); - vec![Ok(Event::default().data("Error reading response"))] + + // Return a more specific error message that can help with debugging + let error_msg = format!("Error reading response: {:?}", e); + + // Send an error event to the client + vec![Ok(Event::default().data(error_msg))] } } }