mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
refactor(access_token): handle timeout errors gracefully (#1882)
This commit is contained in:
@ -11,6 +11,8 @@ pub(crate) const ALPHABETS: [char; 62] = [
|
||||
];
|
||||
/// API client request timeout (in seconds)
|
||||
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";
|
||||
|
||||
///Payment intent fulfillment default timeout (in seconds)
|
||||
pub const DEFAULT_FULFILLMENT_TIME: i64 = 15 * 60;
|
||||
|
||||
@ -186,7 +186,7 @@ pub fn http_not_implemented() -> actix_web::HttpResponse<BoxBody> {
|
||||
.error_response()
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[derive(Debug, thiserror::Error, PartialEq)]
|
||||
pub enum ApiClientError {
|
||||
#[error("Header map construction failed")]
|
||||
HeaderMapConstructionFailed,
|
||||
@ -315,6 +315,8 @@ pub enum ConnectorError {
|
||||
MissingPaymentMethodType,
|
||||
#[error("Balance in the payment method is low")]
|
||||
InSufficientBalanceInPaymentMethod,
|
||||
#[error("Server responded with Request Timeout")]
|
||||
RequestTimeoutReceived,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@ -490,6 +492,18 @@ pub enum WebhooksFlowError {
|
||||
MissingRequiredField { field_name: &'static str },
|
||||
}
|
||||
|
||||
impl ApiClientError {
|
||||
pub fn is_upstream_timeout(&self) -> bool {
|
||||
self == &Self::RequestTimeoutReceived
|
||||
}
|
||||
}
|
||||
|
||||
impl ConnectorError {
|
||||
pub fn is_connector_timeout(&self) -> bool {
|
||||
self == &Self::RequestTimeoutReceived
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "detailed_errors")]
|
||||
pub mod error_stack_parsing {
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ use common_utils::ext_traits::AsyncExt;
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
|
||||
use crate::{
|
||||
consts,
|
||||
core::{
|
||||
errors::{self, RouterResult},
|
||||
payments,
|
||||
@ -151,16 +152,38 @@ pub async fn refresh_connector_auth(
|
||||
types::AccessToken,
|
||||
> = connector.connector.get_connector_integration();
|
||||
|
||||
let access_token_router_data = services::execute_connector_processing_step(
|
||||
let access_token_router_data_result = services::execute_connector_processing_step(
|
||||
state,
|
||||
connector_integration,
|
||||
router_data,
|
||||
payments::CallConnectorAction::Trigger,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.await;
|
||||
|
||||
let access_token_router_data = match access_token_router_data_result {
|
||||
Ok(router_data) => Ok(router_data.response),
|
||||
Err(connector_error) => {
|
||||
// If we receive a timeout error from the connector, then
|
||||
// the error has to be handled gracefully by updating the payment status to failed.
|
||||
// further payment flow will not be continued
|
||||
if connector_error.current_context().is_connector_timeout() {
|
||||
let error_response = types::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: 200,
|
||||
};
|
||||
|
||||
Ok(Err(error_response))
|
||||
} else {
|
||||
Err(connector_error
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Could not refresh access token")?;
|
||||
.attach_printable("Could not refresh access token"))
|
||||
}
|
||||
}
|
||||
}?;
|
||||
|
||||
metrics::ACCESS_TOKEN_CREATION.add(
|
||||
&metrics::CONTEXT,
|
||||
1,
|
||||
@ -169,5 +192,5 @@ pub async fn refresh_connector_auth(
|
||||
connector.connector_name.to_string(),
|
||||
)],
|
||||
);
|
||||
Ok(access_token_router_data.response)
|
||||
Ok(access_token_router_data)
|
||||
}
|
||||
|
||||
@ -325,8 +325,16 @@ where
|
||||
};
|
||||
Ok(response)
|
||||
}
|
||||
Err(error) => Err(error
|
||||
.change_context(errors::ConnectorError::ProcessingStepFailed(None))),
|
||||
Err(error) => {
|
||||
if error.current_context().is_upstream_timeout() {
|
||||
Err(error
|
||||
.change_context(errors::ConnectorError::RequestTimeoutReceived))
|
||||
} else {
|
||||
Err(error.change_context(
|
||||
errors::ConnectorError::ProcessingStepFailed(None),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => Ok(router_data),
|
||||
|
||||
Reference in New Issue
Block a user