Skip to content

Commit d9ce42f

Browse files
Refactor(core): interpolate success_based_routing config params with their specific values (#6448)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent 21d3071 commit d9ce42f

File tree

8 files changed

+188
-46
lines changed

8 files changed

+188
-46
lines changed

crates/api_models/src/routing.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,8 +615,11 @@ impl Default for SuccessBasedRoutingConfig {
615615
pub enum SuccessBasedRoutingConfigParams {
616616
PaymentMethod,
617617
PaymentMethodType,
618-
Currency,
619618
AuthenticationType,
619+
Currency,
620+
Country,
621+
CardNetwork,
622+
CardBin,
620623
}
621624

622625
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema)]

crates/external_services/src/grpc_client.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use std::{fmt::Debug, sync::Arc};
55

66
#[cfg(feature = "dynamic_routing")]
77
use dynamic_routing::{DynamicRoutingClientConfig, RoutingStrategy};
8-
use router_env::logger;
98
use serde;
109

1110
/// Struct contains all the gRPC Clients
@@ -38,8 +37,6 @@ impl GrpcClientSettings {
3837
.await
3938
.expect("Failed to establish a connection with the Dynamic Routing Server");
4039

41-
logger::info!("Connection established with gRPC Server");
42-
4340
Arc::new(GrpcClients {
4441
#[cfg(feature = "dynamic_routing")]
4542
dynamic_routing: dynamic_routing_connection,

crates/external_services/src/grpc_client/dynamic_routing.rs

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use error_stack::ResultExt;
99
use http_body_util::combinators::UnsyncBoxBody;
1010
use hyper::body::Bytes;
1111
use hyper_util::client::legacy::connect::HttpConnector;
12+
use router_env::logger;
1213
use serde;
1314
use success_rate::{
1415
success_rate_calculator_client::SuccessRateCalculatorClient, CalSuccessRateConfig,
@@ -80,6 +81,7 @@ impl DynamicRoutingClientConfig {
8081
let success_rate_client = match self {
8182
Self::Enabled { host, port } => {
8283
let uri = format!("http://{}:{}", host, port).parse::<tonic::transport::Uri>()?;
84+
logger::info!("Connection established with dynamic routing gRPC Server");
8385
Some(SuccessRateCalculatorClient::with_origin(client, uri))
8486
}
8587
Self::Disabled => None,
@@ -98,13 +100,15 @@ pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync {
98100
&self,
99101
id: String,
100102
success_rate_based_config: SuccessBasedRoutingConfig,
103+
params: String,
101104
label_input: Vec<RoutableConnectorChoice>,
102105
) -> DynamicRoutingResult<CalSuccessRateResponse>;
103106
/// To update the success rate with the given label
104107
async fn update_success_rate(
105108
&self,
106109
id: String,
107110
success_rate_based_config: SuccessBasedRoutingConfig,
111+
params: String,
108112
response: Vec<RoutableConnectorChoiceWithStatus>,
109113
) -> DynamicRoutingResult<UpdateSuccessRateWindowResponse>;
110114
}
@@ -115,24 +119,9 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient<Client> {
115119
&self,
116120
id: String,
117121
success_rate_based_config: SuccessBasedRoutingConfig,
122+
params: String,
118123
label_input: Vec<RoutableConnectorChoice>,
119124
) -> DynamicRoutingResult<CalSuccessRateResponse> {
120-
let params = success_rate_based_config
121-
.params
122-
.map(|vec| {
123-
vec.into_iter().fold(String::new(), |mut acc_str, params| {
124-
if !acc_str.is_empty() {
125-
acc_str.push(':')
126-
}
127-
acc_str.push_str(params.to_string().as_str());
128-
acc_str
129-
})
130-
})
131-
.get_required_value("params")
132-
.change_context(DynamicRoutingError::MissingRequiredField {
133-
field: "params".to_string(),
134-
})?;
135-
136125
let labels = label_input
137126
.into_iter()
138127
.map(|conn_choice| conn_choice.to_string())
@@ -167,6 +156,7 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient<Client> {
167156
&self,
168157
id: String,
169158
success_rate_based_config: SuccessBasedRoutingConfig,
159+
params: String,
170160
label_input: Vec<RoutableConnectorChoiceWithStatus>,
171161
) -> DynamicRoutingResult<UpdateSuccessRateWindowResponse> {
172162
let config = success_rate_based_config
@@ -182,22 +172,6 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient<Client> {
182172
})
183173
.collect();
184174

185-
let params = success_rate_based_config
186-
.params
187-
.map(|vec| {
188-
vec.into_iter().fold(String::new(), |mut acc_str, params| {
189-
if !acc_str.is_empty() {
190-
acc_str.push(':')
191-
}
192-
acc_str.push_str(params.to_string().as_str());
193-
acc_str
194-
})
195-
})
196-
.get_required_value("params")
197-
.change_context(DynamicRoutingError::MissingRequiredField {
198-
field: "params".to_string(),
199-
})?;
200-
201175
let request = tonic::Request::new(UpdateSuccessRateWindowRequest {
202176
id,
203177
params,

crates/router/src/core/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ pub enum RoutingError {
330330
MetadataParsingError,
331331
#[error("Unable to retrieve success based routing config")]
332332
SuccessBasedRoutingConfigError,
333+
#[error("Params not found in success based routing config")]
334+
SuccessBasedRoutingParamsNotFoundError,
333335
#[error("Unable to calculate success based routing config from dynamic routing service")]
334336
SuccessRateCalculationError,
335337
#[error("Success rate client from dynamic routing gRPC service not initialized")]

crates/router/src/core/payments.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ use super::{
7272
#[cfg(feature = "frm")]
7373
use crate::core::fraud_check as frm_core;
7474
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
75+
use crate::core::routing::helpers as routing_helpers;
76+
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
7577
use crate::types::api::convert_connector_data_to_routable_connectors;
7678
use crate::{
7779
configs::settings::{ApplePayPreDecryptFlow, PaymentMethodTypeTokenFilter},
@@ -5580,10 +5582,46 @@ where
55805582
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
55815583
let connectors = {
55825584
if business_profile.dynamic_routing_algorithm.is_some() {
5583-
routing::perform_success_based_routing(state, connectors.clone(), business_profile)
5584-
.await
5585-
.map_err(|e| logger::error!(success_rate_routing_error=?e))
5586-
.unwrap_or(connectors)
5585+
let success_based_routing_config_params_interpolator =
5586+
routing_helpers::SuccessBasedRoutingConfigParamsInterpolator::new(
5587+
payment_data.get_payment_attempt().payment_method,
5588+
payment_data.get_payment_attempt().payment_method_type,
5589+
payment_data.get_payment_attempt().authentication_type,
5590+
payment_data.get_payment_attempt().currency,
5591+
payment_data
5592+
.get_billing_address()
5593+
.and_then(|address| address.address)
5594+
.and_then(|address| address.country),
5595+
payment_data
5596+
.get_payment_attempt()
5597+
.payment_method_data
5598+
.as_ref()
5599+
.and_then(|data| data.as_object())
5600+
.and_then(|card| card.get("card"))
5601+
.and_then(|data| data.as_object())
5602+
.and_then(|card| card.get("card_network"))
5603+
.and_then(|network| network.as_str())
5604+
.map(|network| network.to_string()),
5605+
payment_data
5606+
.get_payment_attempt()
5607+
.payment_method_data
5608+
.as_ref()
5609+
.and_then(|data| data.as_object())
5610+
.and_then(|card| card.get("card"))
5611+
.and_then(|data| data.as_object())
5612+
.and_then(|card| card.get("card_isin"))
5613+
.and_then(|card_isin| card_isin.as_str())
5614+
.map(|card_isin| card_isin.to_string()),
5615+
);
5616+
routing::perform_success_based_routing(
5617+
state,
5618+
connectors.clone(),
5619+
business_profile,
5620+
success_based_routing_config_params_interpolator,
5621+
)
5622+
.await
5623+
.map_err(|e| logger::error!(success_rate_routing_error=?e))
5624+
.unwrap_or(connectors)
55875625
} else {
55885626
connectors
55895627
}

crates/router/src/core/payments/operations/payment_response.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use tracing_futures::Instrument;
2121

2222
use super::{Operation, OperationSessionSetters, PostUpdateTracker};
2323
#[cfg(all(feature = "v1", feature = "dynamic_routing"))]
24-
use crate::core::routing::helpers::push_metrics_for_success_based_routing;
24+
use crate::core::routing::helpers as routing_helpers;
2525
use crate::{
2626
connector::utils::PaymentResponseRouterData,
2727
consts,
@@ -1968,13 +1968,44 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
19681968
let state = state.clone();
19691969
let business_profile = business_profile.clone();
19701970
let payment_attempt = payment_attempt.clone();
1971+
let success_based_routing_config_params_interpolator =
1972+
routing_helpers::SuccessBasedRoutingConfigParamsInterpolator::new(
1973+
payment_attempt.payment_method,
1974+
payment_attempt.payment_method_type,
1975+
payment_attempt.authentication_type,
1976+
payment_attempt.currency,
1977+
payment_data
1978+
.address
1979+
.get_payment_billing()
1980+
.and_then(|address| address.clone().address)
1981+
.and_then(|address| address.country),
1982+
payment_attempt
1983+
.payment_method_data
1984+
.as_ref()
1985+
.and_then(|data| data.as_object())
1986+
.and_then(|card| card.get("card"))
1987+
.and_then(|data| data.as_object())
1988+
.and_then(|card| card.get("card_network"))
1989+
.and_then(|network| network.as_str())
1990+
.map(|network| network.to_string()),
1991+
payment_attempt
1992+
.payment_method_data
1993+
.as_ref()
1994+
.and_then(|data| data.as_object())
1995+
.and_then(|card| card.get("card"))
1996+
.and_then(|data| data.as_object())
1997+
.and_then(|card| card.get("card_isin"))
1998+
.and_then(|card_isin| card_isin.as_str())
1999+
.map(|card_isin| card_isin.to_string()),
2000+
);
19712001
tokio::spawn(
19722002
async move {
1973-
push_metrics_for_success_based_routing(
2003+
routing_helpers::push_metrics_with_update_window_for_success_based_routing(
19742004
&state,
19752005
&payment_attempt,
19762006
routable_connectors,
19772007
&business_profile,
2008+
success_based_routing_config_params_interpolator,
19782009
)
19792010
.await
19802011
.map_err(|e| logger::error!(dynamic_routing_metrics_error=?e))
@@ -1984,6 +2015,7 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
19842015
);
19852016
}
19862017
}
2018+
19872019
payment_data.payment_intent = payment_intent;
19882020
payment_data.payment_attempt = payment_attempt;
19892021
router_data.payment_method_status.and_then(|status| {

crates/router/src/core/payments/routing.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,7 @@ pub async fn perform_success_based_routing(
12401240
state: &SessionState,
12411241
routable_connectors: Vec<api_routing::RoutableConnectorChoice>,
12421242
business_profile: &domain::Profile,
1243+
success_based_routing_config_params_interpolator: routing::helpers::SuccessBasedRoutingConfigParamsInterpolator,
12431244
) -> RoutingResult<Vec<api_routing::RoutableConnectorChoice>> {
12441245
let success_based_dynamic_routing_algo_ref: api_routing::DynamicRoutingAlgorithmRef =
12451246
business_profile
@@ -1293,6 +1294,14 @@ pub async fn perform_success_based_routing(
12931294
.change_context(errors::RoutingError::SuccessBasedRoutingConfigError)
12941295
.attach_printable("unable to fetch success_rate based dynamic routing configs")?;
12951296

1297+
let success_based_routing_config_params = success_based_routing_config_params_interpolator
1298+
.get_string_val(
1299+
success_based_routing_configs
1300+
.params
1301+
.as_ref()
1302+
.ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError)?,
1303+
);
1304+
12961305
let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id(
12971306
&state.tenant.redis_key_prefix,
12981307
business_profile.get_id().get_string_repr(),
@@ -1302,6 +1311,7 @@ pub async fn perform_success_based_routing(
13021311
.calculate_success_rate(
13031312
tenant_business_profile_id,
13041313
success_based_routing_configs,
1314+
success_based_routing_config_params,
13051315
routable_connectors,
13061316
)
13071317
.await

0 commit comments

Comments
 (0)