mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 21:07:58 +08:00
feat(router): send connector timeouts and connection closures as 2xx response instead of giving 5xx response (#2047)
This commit is contained in:
committed by
GitHub
parent
c9fe389b2c
commit
31088b6062
@ -13,6 +13,9 @@ pub(crate) const ALPHABETS: [char; 62] = [
|
||||
pub const REQUEST_TIME_OUT: u64 = 30;
|
||||
pub const REQUEST_TIMEOUT_ERROR_CODE: &str = "TIMEOUT";
|
||||
pub const REQUEST_TIMEOUT_ERROR_MESSAGE: &str = "Connector did not respond in specified time";
|
||||
pub const CONNECTION_CLOSED_ERROR_CODE: &str = "CONNECTION_CLOSED";
|
||||
pub const CONNECTION_CLOSED_ERROR_MESSAGE: &str =
|
||||
"Connection closed before a message could complete";
|
||||
|
||||
///Payment intent fulfillment default timeout (in seconds)
|
||||
pub const DEFAULT_FULFILLMENT_TIME: i64 = 15 * 60;
|
||||
|
||||
@ -273,6 +273,9 @@ pub enum ApiClientError {
|
||||
#[error("Server responded with Request Timeout")]
|
||||
RequestTimeoutReceived,
|
||||
|
||||
#[error("connection closed before a message could complete")]
|
||||
ConnectionClosed,
|
||||
|
||||
#[error("Server responded with Internal Server Error")]
|
||||
InternalServerErrorReceived,
|
||||
#[error("Server responded with Bad Gateway")]
|
||||
@ -566,6 +569,9 @@ impl ApiClientError {
|
||||
pub fn is_upstream_timeout(&self) -> bool {
|
||||
self == &Self::RequestTimeoutReceived
|
||||
}
|
||||
pub fn is_connection_closed(&self) -> bool {
|
||||
self == &Self::ConnectionClosed
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectorError {
|
||||
|
||||
@ -172,7 +172,7 @@ pub async fn refresh_connector_auth(
|
||||
code: consts::REQUEST_TIMEOUT_ERROR_CODE.to_string(),
|
||||
message: consts::REQUEST_TIMEOUT_ERROR_MESSAGE.to_string(),
|
||||
reason: Some(consts::REQUEST_TIMEOUT_ERROR_MESSAGE.to_string()),
|
||||
status_code: 200,
|
||||
status_code: 504,
|
||||
};
|
||||
|
||||
Ok(Err(error_response))
|
||||
|
||||
@ -3,6 +3,7 @@ pub mod request;
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
error::Error,
|
||||
fmt::Debug,
|
||||
future::Future,
|
||||
str,
|
||||
@ -384,8 +385,27 @@ where
|
||||
}
|
||||
Err(error) => {
|
||||
if error.current_context().is_upstream_timeout() {
|
||||
Err(error
|
||||
.change_context(errors::ConnectorError::RequestTimeoutReceived))
|
||||
let error_response = ErrorResponse {
|
||||
code: consts::REQUEST_TIMEOUT_ERROR_CODE.to_string(),
|
||||
message: consts::REQUEST_TIMEOUT_ERROR_MESSAGE.to_string(),
|
||||
reason: Some(consts::REQUEST_TIMEOUT_ERROR_MESSAGE.to_string()),
|
||||
status_code: 504,
|
||||
};
|
||||
router_data.response = Err(error_response);
|
||||
router_data.connector_http_status_code = Some(504);
|
||||
Ok(router_data)
|
||||
} else if error.current_context().is_connection_closed() {
|
||||
let error_response = ErrorResponse {
|
||||
code: consts::CONNECTION_CLOSED_ERROR_CODE.to_string(),
|
||||
message: consts::CONNECTION_CLOSED_ERROR_MESSAGE.to_string(),
|
||||
reason: Some(
|
||||
consts::CONNECTION_CLOSED_ERROR_MESSAGE.to_string(),
|
||||
),
|
||||
status_code: 504,
|
||||
};
|
||||
router_data.response = Err(error_response);
|
||||
router_data.connector_http_status_code = Some(504);
|
||||
Ok(router_data)
|
||||
} else {
|
||||
Err(error.change_context(
|
||||
errors::ConnectorError::ProcessingStepFailed(None),
|
||||
@ -505,6 +525,10 @@ pub async fn send_request(
|
||||
metrics::REQUEST_BUILD_FAILURE.add(&metrics::CONTEXT, 1, &[]);
|
||||
errors::ApiClientError::RequestTimeoutReceived
|
||||
}
|
||||
error if is_connection_closed(&error) => {
|
||||
metrics::REQUEST_BUILD_FAILURE.add(&metrics::CONTEXT, 1, &[]);
|
||||
errors::ApiClientError::ConnectionClosed
|
||||
}
|
||||
_ => errors::ApiClientError::RequestNotSent(error.to_string()),
|
||||
})
|
||||
.into_report()
|
||||
@ -519,6 +543,19 @@ pub async fn send_request(
|
||||
.await
|
||||
}
|
||||
|
||||
fn is_connection_closed(error: &reqwest::Error) -> bool {
|
||||
let mut source = error.source();
|
||||
while let Some(err) = source {
|
||||
if let Some(hyper_err) = err.downcast_ref::<hyper::Error>() {
|
||||
if hyper_err.is_incomplete_message() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
source = err.source();
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn handle_response(
|
||||
response: CustomResult<reqwest::Response, errors::ApiClientError>,
|
||||
|
||||
Reference in New Issue
Block a user