From aec9188d36fe736caeadc7c32b5b301fdcb8eafa Mon Sep 17 00:00:00 2001 From: khanova <32508607+khanova@users.noreply.github.com> Date: Tue, 10 Oct 2023 13:39:38 +0200 Subject: [PATCH] Added timeout for http requests (#5514) # Problem Proxy timeout for HTTP-requests ## Summary of changes If the HTTP-request exceeds 15s, it would be killed. Resolves: https://github.com/neondatabase/neon/issues/4847 --- proxy/src/http/sql_over_http.rs | 52 ++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/proxy/src/http/sql_over_http.rs b/proxy/src/http/sql_over_http.rs index 380e36d530..ffc788e873 100644 --- a/proxy/src/http/sql_over_http.rs +++ b/proxy/src/http/sql_over_http.rs @@ -47,6 +47,7 @@ enum Payload { const MAX_RESPONSE_SIZE: usize = 10 * 1024 * 1024; // 10 MiB const MAX_REQUEST_SIZE: u64 = 10 * 1024 * 1024; // 10 MiB +const HTTP_CONNECTION_TIMEOUT: tokio::time::Duration = tokio::time::Duration::from_secs(15); static RAW_TEXT_OUTPUT: HeaderName = HeaderName::from_static("neon-raw-text-output"); static ARRAY_MODE: HeaderName = HeaderName::from_static("neon-array-mode"); @@ -189,27 +190,44 @@ pub async fn handle( conn_pool: Arc, session_id: uuid::Uuid, ) -> Result, ApiError> { - let result = handle_inner(request, sni_hostname, conn_pool, session_id).await; - + let result = tokio::time::timeout( + HTTP_CONNECTION_TIMEOUT, + handle_inner(request, sni_hostname, conn_pool, session_id), + ) + .await; let mut response = match result { - Ok(r) => r, - Err(e) => { - let message = format!("{:?}", e); - let code = match e.downcast_ref::() { - Some(e) => match e.code() { - Some(e) => serde_json::to_value(e.code()).unwrap(), + Ok(r) => match r { + Ok(r) => r, + Err(e) => { + let message = format!("{:?}", e); + let code = e.downcast_ref::().and_then(|e| { + e.code() + .map(|s| serde_json::to_value(s.code()).unwrap_or_default()) + }); + let code = match code { + Some(c) => c, None => Value::Null, - }, - None => Value::Null, - }; - error!( - ?code, - "sql-over-http per-client task finished with an error: {e:#}" + }; + error!( + ?code, + "sql-over-http per-client task finished with an error: {e:#}" + ); + // TODO: this shouldn't always be bad request. + json_response( + StatusCode::BAD_REQUEST, + json!({ "message": message, "code": code }), + )? + } + }, + Err(_) => { + let message = format!( + "HTTP-Connection timed out, execution time exeeded {} seconds", + HTTP_CONNECTION_TIMEOUT.as_secs() ); - // TODO: this shouldn't always be bad request. + error!(message); json_response( - StatusCode::BAD_REQUEST, - json!({ "message": message, "code": code }), + StatusCode::GATEWAY_TIMEOUT, + json!({ "message": message, "code": StatusCode::GATEWAY_TIMEOUT.as_u16() }), )? } };