From 99bb911281286920d29b4053dc4fdcf0cbe513d3 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Mon, 28 Oct 2024 11:42:08 +0530 Subject: [PATCH 01/19] init: param interpolation --- crates/api_models/src/routing.rs | 14 +++++++++----- crates/router/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 47d75b2e8357..8434a27d8735 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -597,7 +597,7 @@ pub struct SuccessBasedRoutingConfig { impl Default for SuccessBasedRoutingConfig { fn default() -> Self { Self { - params: Some(vec![SuccessBasedRoutingConfigParams::PaymentMethod]), + params: Some(vec![SuccessBasedRoutingConfigParams::PaymentMethod(common_enums::PaymentMethod::Card)]), config: Some(SuccessBasedRoutingConfigBody { min_aggregates_size: Some(2), default_success_rate: Some(100.0), @@ -613,10 +613,14 @@ impl Default for SuccessBasedRoutingConfig { #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema, strum::Display)] pub enum SuccessBasedRoutingConfigParams { - PaymentMethod, - PaymentMethodType, - Currency, - AuthenticationType, + PaymentMethod(common_enums::PaymentMethod), + PaymentMethodType(common_enums::PaymentMethodType), + AuthenticationType(common_enums::AuthenticationType), + Currency(common_enums::Currency), + PaymentType(common_enums::PaymentType), + Country(common_enums::Country), + CardNetwork(common_enums::CardNetwork), + CardBin(String), } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema)] diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index b794443a047f..e197d41b469d 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true [features] default = ["common_default", "v1"] -common_default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] +common_default = ["dynamic_routing","kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] olap = ["hyperswitch_domain_models/olap", "storage_impl/olap", "scheduler/olap", "api_models/olap", "dep:analytics"] tls = ["actix-web/rustls-0_22"] email = ["external_services/email", "scheduler/email", "olap"] From bc9cdda5fe8b58f4b7ea6f00570b44fe6c74428b Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Mon, 28 Oct 2024 11:54:14 +0530 Subject: [PATCH 02/19] remove dynamic_routing from cargo.toml --- crates/router/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index e197d41b469d..b794443a047f 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true [features] default = ["common_default", "v1"] -common_default = ["dynamic_routing","kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] +common_default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] olap = ["hyperswitch_domain_models/olap", "storage_impl/olap", "scheduler/olap", "api_models/olap", "dep:analytics"] tls = ["actix-web/rustls-0_22"] email = ["external_services/email", "scheduler/email", "olap"] From 510164d19573ac0455844e8393a6252f92232217 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:12:47 +0000 Subject: [PATCH 03/19] chore: run formatter --- crates/api_models/src/routing.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 8434a27d8735..7733085e2c65 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -597,7 +597,9 @@ pub struct SuccessBasedRoutingConfig { impl Default for SuccessBasedRoutingConfig { fn default() -> Self { Self { - params: Some(vec![SuccessBasedRoutingConfigParams::PaymentMethod(common_enums::PaymentMethod::Card)]), + params: Some(vec![SuccessBasedRoutingConfigParams::PaymentMethod( + common_enums::PaymentMethod::Card, + )]), config: Some(SuccessBasedRoutingConfigBody { min_aggregates_size: Some(2), default_success_rate: Some(100.0), From db90e5d67f056d05721cf11ffd89fe0da411850d Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Mon, 28 Oct 2024 22:54:38 +0530 Subject: [PATCH 04/19] interpolation function --- config/development.toml | 4 ++ crates/api_models/src/routing.rs | 18 +++---- .../src/grpc_client/dynamic_routing.rs | 32 +++++------ crates/router/Cargo.toml | 2 +- crates/router/src/core/payments.rs | 2 +- crates/router/src/core/payments/routing.rs | 54 +++++++++++++++++-- 6 files changed, 83 insertions(+), 29 deletions(-) diff --git a/config/development.toml b/config/development.toml index d32c36101323..0f33f22d3dd8 100644 --- a/config/development.toml +++ b/config/development.toml @@ -766,3 +766,7 @@ card_networks = "Visa, AmericanExpress, Mastercard" [network_tokenization_supported_connectors] connector_list = "cybersource" + +[grpc_client.dynamic_routing_client] +host = "localhost" +port = 7000 diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 8434a27d8735..85b8f8760944 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -597,7 +597,7 @@ pub struct SuccessBasedRoutingConfig { impl Default for SuccessBasedRoutingConfig { fn default() -> Self { Self { - params: Some(vec![SuccessBasedRoutingConfigParams::PaymentMethod(common_enums::PaymentMethod::Card)]), + params: Some(vec![SuccessBasedRoutingConfigParams::PaymentMethod]), config: Some(SuccessBasedRoutingConfigBody { min_aggregates_size: Some(2), default_success_rate: Some(100.0), @@ -613,14 +613,14 @@ impl Default for SuccessBasedRoutingConfig { #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema, strum::Display)] pub enum SuccessBasedRoutingConfigParams { - PaymentMethod(common_enums::PaymentMethod), - PaymentMethodType(common_enums::PaymentMethodType), - AuthenticationType(common_enums::AuthenticationType), - Currency(common_enums::Currency), - PaymentType(common_enums::PaymentType), - Country(common_enums::Country), - CardNetwork(common_enums::CardNetwork), - CardBin(String), + PaymentMethod, + PaymentMethodType, + AuthenticationType, + Currency, + PaymentType, + Country, + CardNetwork, + CardBin, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema)] diff --git a/crates/external_services/src/grpc_client/dynamic_routing.rs b/crates/external_services/src/grpc_client/dynamic_routing.rs index 2681bffb0ce3..49fbe5b0a864 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing.rs @@ -90,6 +90,7 @@ pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync { &self, id: String, success_rate_based_config: SuccessBasedRoutingConfig, + params: String, label_input: Vec, ) -> DynamicRoutingResult; /// To update the success rate with the given label @@ -107,23 +108,24 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { &self, id: String, success_rate_based_config: SuccessBasedRoutingConfig, + params: String, label_input: Vec, ) -> DynamicRoutingResult { - let params = success_rate_based_config - .params - .map(|vec| { - vec.into_iter().fold(String::new(), |mut acc_str, params| { - if !acc_str.is_empty() { - acc_str.push(':') - } - acc_str.push_str(params.to_string().as_str()); - acc_str - }) - }) - .get_required_value("params") - .change_context(DynamicRoutingError::MissingRequiredField { - field: "params".to_string(), - })?; + // let params = success_rate_based_config + // .params + // .map(|vec| { + // vec.into_iter().fold(String::new(), |mut acc_str, params| { + // if !acc_str.is_empty() { + // acc_str.push(':') + // } + // acc_str.push_str(params.to_string().as_str()); + // acc_str + // }) + // }) + // .get_required_value("params") + // .change_context(DynamicRoutingError::MissingRequiredField { + // field: "params".to_string(), + // })?; let labels = label_input .into_iter() diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index b794443a047f..e197d41b469d 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true [features] default = ["common_default", "v1"] -common_default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] +common_default = ["dynamic_routing","kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] olap = ["hyperswitch_domain_models/olap", "storage_impl/olap", "scheduler/olap", "api_models/olap", "dep:analytics"] tls = ["actix-web/rustls-0_22"] email = ["external_services/email", "scheduler/email", "olap"] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index de58eeed1008..40572ca6be96 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5587,7 +5587,7 @@ where #[cfg(all(feature = "v1", feature = "dynamic_routing"))] let connectors = { if business_profile.dynamic_routing_algorithm.is_some() { - routing::perform_success_based_routing(state, connectors.clone(), business_profile) + routing::perform_success_based_routing(state, connectors.clone(), business_profile, payment_data) .await .map_err(|e| logger::error!(success_rate_routing_error=?e)) .unwrap_or(connectors) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 40721e9b4c31..db64c506a120 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -39,7 +39,7 @@ use rand::{ }; use rustc_hash::FxHashMap; use storage_impl::redis::cache::{CacheKey, CGRAPH_CACHE, ROUTING_CACHE}; - +use super::{OperationSessionGetters, OperationSessionSetters}; #[cfg(feature = "v2")] use crate::core::admin; #[cfg(feature = "payouts")] @@ -1236,11 +1236,17 @@ pub fn make_dsl_input_for_surcharge( /// success based dynamic routing #[cfg(all(feature = "v1", feature = "dynamic_routing"))] -pub async fn perform_success_based_routing( +pub async fn perform_success_based_routing( state: &SessionState, routable_connectors: Vec, business_profile: &domain::Profile, -) -> RoutingResult> { + payment_data: &D, +) -> RoutingResult> +where + F: Send + Clone, + D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, +{ + let success_based_dynamic_routing_algo_ref: api_routing::DynamicRoutingAlgorithmRef = business_profile .dynamic_routing_algorithm @@ -1293,6 +1299,8 @@ pub async fn perform_success_based_routing( .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) .attach_printable("unable to fetch success_rate based dynamic routing configs")?; + let success_based_routing_config_params = interpolate_success_based_routing_params(success_based_routing_configs, payment_data); + let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, business_profile.get_id().get_string_repr(), @@ -1344,3 +1352,43 @@ pub async fn perform_success_based_routing( Ok(routable_connectors) } } + +pub async fn interpolate_success_based_routing_params( + success_rate_based_config: api_routing::SuccessBasedRoutingConfig, + payment_data: &D, +) -> Vec +where + F: Send + Clone, + D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, +{ + let mut res = Vec::new(); + for param in success_rate_based_config.params.unwrap() { + let val:String = match param { + api_routing::SuccessBasedRoutingConfigParams::PaymentMethod => payment_data.get_payment_attempt().payment_method.unwrap().to_string(), + api_routing::SuccessBasedRoutingConfigParams::PaymentMethodType => payment_data.get_payment_attempt().get_payment_method_type().unwrap().to_string(), + api_routing::SuccessBasedRoutingConfigParams::AuthenticationType => payment_data.get_payment_attempt().authentication_type.unwrap().to_string(), + api_routing::SuccessBasedRoutingConfigParams::Currency => payment_data.get_currency().to_string(), + api_routing::SuccessBasedRoutingConfigParams::Country => payment_data.get_billing_address().unwrap().address.unwrap().country.unwrap().to_string(), + api_routing::SuccessBasedRoutingConfigParams::PaymentType => todo!(), + api_routing::SuccessBasedRoutingConfigParams::CardNetwork => + payment_data.get_payment_attempt().payment_method_data.as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_network")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()).unwrap(), + api_routing::SuccessBasedRoutingConfigParams::CardBin => + payment_data.get_payment_attempt().payment_method_data.as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_number")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()).unwrap(), + }; + res.push(val); + } + res + +} From bd1dff111d958b2a0f1280dc51f52b9a0ea1f828 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:26:14 +0000 Subject: [PATCH 05/19] chore: run formatter --- crates/router/src/core/payments.rs | 13 ++-- crates/router/src/core/payments/routing.rs | 83 ++++++++++++++-------- 2 files changed, 64 insertions(+), 32 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 40572ca6be96..c27e70e1eedc 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5587,10 +5587,15 @@ where #[cfg(all(feature = "v1", feature = "dynamic_routing"))] let connectors = { if business_profile.dynamic_routing_algorithm.is_some() { - routing::perform_success_based_routing(state, connectors.clone(), business_profile, payment_data) - .await - .map_err(|e| logger::error!(success_rate_routing_error=?e)) - .unwrap_or(connectors) + routing::perform_success_based_routing( + state, + connectors.clone(), + business_profile, + payment_data, + ) + .await + .map_err(|e| logger::error!(success_rate_routing_error=?e)) + .unwrap_or(connectors) } else { connectors } diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index db64c506a120..9a54a0b3a67d 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -39,6 +39,7 @@ use rand::{ }; use rustc_hash::FxHashMap; use storage_impl::redis::cache::{CacheKey, CGRAPH_CACHE, ROUTING_CACHE}; + use super::{OperationSessionGetters, OperationSessionSetters}; #[cfg(feature = "v2")] use crate::core::admin; @@ -1241,12 +1242,11 @@ pub async fn perform_success_based_routing( routable_connectors: Vec, business_profile: &domain::Profile, payment_data: &D, -) -> RoutingResult> +) -> RoutingResult> where F: Send + Clone, D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { - let success_based_dynamic_routing_algo_ref: api_routing::DynamicRoutingAlgorithmRef = business_profile .dynamic_routing_algorithm @@ -1299,7 +1299,8 @@ where .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) .attach_printable("unable to fetch success_rate based dynamic routing configs")?; - let success_based_routing_config_params = interpolate_success_based_routing_params(success_based_routing_configs, payment_data); + let success_based_routing_config_params = + interpolate_success_based_routing_params(success_based_routing_configs, payment_data); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, @@ -1363,32 +1364,58 @@ where { let mut res = Vec::new(); for param in success_rate_based_config.params.unwrap() { - let val:String = match param { - api_routing::SuccessBasedRoutingConfigParams::PaymentMethod => payment_data.get_payment_attempt().payment_method.unwrap().to_string(), - api_routing::SuccessBasedRoutingConfigParams::PaymentMethodType => payment_data.get_payment_attempt().get_payment_method_type().unwrap().to_string(), - api_routing::SuccessBasedRoutingConfigParams::AuthenticationType => payment_data.get_payment_attempt().authentication_type.unwrap().to_string(), - api_routing::SuccessBasedRoutingConfigParams::Currency => payment_data.get_currency().to_string(), - api_routing::SuccessBasedRoutingConfigParams::Country => payment_data.get_billing_address().unwrap().address.unwrap().country.unwrap().to_string(), - api_routing::SuccessBasedRoutingConfigParams::PaymentType => todo!(), - api_routing::SuccessBasedRoutingConfigParams::CardNetwork => - payment_data.get_payment_attempt().payment_method_data.as_ref() - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card")) - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card_network")) - .and_then(|network| network.as_str()) - .map(|network| network.to_string()).unwrap(), - api_routing::SuccessBasedRoutingConfigParams::CardBin => - payment_data.get_payment_attempt().payment_method_data.as_ref() - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card")) - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card_number")) - .and_then(|network| network.as_str()) - .map(|network| network.to_string()).unwrap(), - }; + let val: String = match param { + api_routing::SuccessBasedRoutingConfigParams::PaymentMethod => payment_data + .get_payment_attempt() + .payment_method + .unwrap() + .to_string(), + api_routing::SuccessBasedRoutingConfigParams::PaymentMethodType => payment_data + .get_payment_attempt() + .get_payment_method_type() + .unwrap() + .to_string(), + api_routing::SuccessBasedRoutingConfigParams::AuthenticationType => payment_data + .get_payment_attempt() + .authentication_type + .unwrap() + .to_string(), + api_routing::SuccessBasedRoutingConfigParams::Currency => { + payment_data.get_currency().to_string() + } + api_routing::SuccessBasedRoutingConfigParams::Country => payment_data + .get_billing_address() + .unwrap() + .address + .unwrap() + .country + .unwrap() + .to_string(), + api_routing::SuccessBasedRoutingConfigParams::PaymentType => todo!(), + api_routing::SuccessBasedRoutingConfigParams::CardNetwork => payment_data + .get_payment_attempt() + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_network")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()) + .unwrap(), + api_routing::SuccessBasedRoutingConfigParams::CardBin => payment_data + .get_payment_attempt() + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_number")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()) + .unwrap(), + }; res.push(val); } res - } From fc4fb38eeedce75bcd91cade8640138c3395ac49 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Tue, 29 Oct 2024 12:54:13 +0530 Subject: [PATCH 06/19] add helper functtion --- crates/api_models/src/routing.rs | 1 - .../payments/operations/payment_response.rs | 21 ++--- crates/router/src/core/payments/routing.rs | 71 +--------------- crates/router/src/core/routing/helpers.rs | 82 ++++++++++++++++++- 4 files changed, 93 insertions(+), 82 deletions(-) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 85b8f8760944..389af3dab7bf 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -617,7 +617,6 @@ pub enum SuccessBasedRoutingConfigParams { PaymentMethodType, AuthenticationType, Currency, - PaymentType, Country, CardNetwork, CardBin, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index a18996ccc3b7..fe6a22df9033 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1916,17 +1916,26 @@ async fn payment_response_update_tracker( utils::flatten_join_error(payment_attempt_fut) )?; + payment_data.payment_intent = payment_intent; + payment_data.payment_attempt = payment_attempt; + router_data.payment_method_status.and_then(|status| { + payment_data + .payment_method_info + .as_mut() + .map(|info| info.status = status) + }); + #[cfg(all(feature = "v1", feature = "dynamic_routing"))] { if business_profile.dynamic_routing_algorithm.is_some() { let state = state.clone(); let business_profile = business_profile.clone(); - let payment_attempt = payment_attempt.clone(); + let payment_data = payment_data.clone(); tokio::spawn( async move { push_metrics_for_success_based_routing( &state, - &payment_attempt, + &payment_data, routable_connectors, &business_profile, ) @@ -1938,14 +1947,6 @@ async fn payment_response_update_tracker( ); } } - payment_data.payment_intent = payment_intent; - payment_data.payment_attempt = payment_attempt; - router_data.payment_method_status.and_then(|status| { - payment_data - .payment_method_info - .as_mut() - .map(|info| info.status = status) - }); match router_data.integrity_check { Ok(()) => Ok(payment_data), diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 9a54a0b3a67d..cef9ac54a3c8 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1247,6 +1247,8 @@ where F: Send + Clone, D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { + use crate::core::routing::helpers::interpolate_success_based_routing_params; + let success_based_dynamic_routing_algo_ref: api_routing::DynamicRoutingAlgorithmRef = business_profile .dynamic_routing_algorithm @@ -1300,7 +1302,7 @@ where .attach_printable("unable to fetch success_rate based dynamic routing configs")?; let success_based_routing_config_params = - interpolate_success_based_routing_params(success_based_routing_configs, payment_data); + interpolate_success_based_routing_params(success_based_routing_configs.clone(), payment_data); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, @@ -1311,6 +1313,7 @@ where .calculate_success_rate( tenant_business_profile_id, success_based_routing_configs, + success_based_routing_config_params, routable_connectors, ) .await @@ -1353,69 +1356,3 @@ where Ok(routable_connectors) } } - -pub async fn interpolate_success_based_routing_params( - success_rate_based_config: api_routing::SuccessBasedRoutingConfig, - payment_data: &D, -) -> Vec -where - F: Send + Clone, - D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, -{ - let mut res = Vec::new(); - for param in success_rate_based_config.params.unwrap() { - let val: String = match param { - api_routing::SuccessBasedRoutingConfigParams::PaymentMethod => payment_data - .get_payment_attempt() - .payment_method - .unwrap() - .to_string(), - api_routing::SuccessBasedRoutingConfigParams::PaymentMethodType => payment_data - .get_payment_attempt() - .get_payment_method_type() - .unwrap() - .to_string(), - api_routing::SuccessBasedRoutingConfigParams::AuthenticationType => payment_data - .get_payment_attempt() - .authentication_type - .unwrap() - .to_string(), - api_routing::SuccessBasedRoutingConfigParams::Currency => { - payment_data.get_currency().to_string() - } - api_routing::SuccessBasedRoutingConfigParams::Country => payment_data - .get_billing_address() - .unwrap() - .address - .unwrap() - .country - .unwrap() - .to_string(), - api_routing::SuccessBasedRoutingConfigParams::PaymentType => todo!(), - api_routing::SuccessBasedRoutingConfigParams::CardNetwork => payment_data - .get_payment_attempt() - .payment_method_data - .as_ref() - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card")) - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card_network")) - .and_then(|network| network.as_str()) - .map(|network| network.to_string()) - .unwrap(), - api_routing::SuccessBasedRoutingConfigParams::CardBin => payment_data - .get_payment_attempt() - .payment_method_data - .as_ref() - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card")) - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card_number")) - .and_then(|network| network.as_str()) - .map(|network| network.to_string()) - .unwrap(), - }; - res.push(val); - } - res -} diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 6b5845831745..7225b2a30206 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -29,7 +29,7 @@ use storage_impl::redis::cache; #[cfg(feature = "v2")] use crate::types::domain::MerchantConnectorAccount; use crate::{ - core::errors::{self, RouterResult}, + core::{errors::{self, RouterResult}, payments::{OperationSessionGetters, OperationSessionSetters}}, db::StorageInterface, routes::SessionState, types::{domain, storage}, @@ -640,12 +640,17 @@ pub async fn fetch_success_based_routing_configs( /// metrics for success based dynamic routing #[cfg(all(feature = "v1", feature = "dynamic_routing"))] #[instrument(skip_all)] -pub async fn push_metrics_for_success_based_routing( +pub async fn push_metrics_for_success_based_routing( state: &SessionState, - payment_attempt: &storage::PaymentAttempt, + payment_data: &D, routable_connectors: Vec, business_profile: &domain::Profile, -) -> RouterResult<()> { +) -> RouterResult<()> +where + F: Clone, + D: OperationSessionGetters + OperationSessionSetters + Clone, +{ + let payment_attempt = payment_data.get_payment_attempt(); let success_based_dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef = business_profile .dynamic_routing_algorithm @@ -697,10 +702,14 @@ pub async fn push_metrics_for_success_based_routing( business_profile.get_id().get_string_repr(), ); + let success_based_routing_config_params = + interpolate_success_based_routing_params(success_based_routing_configs.clone(), payment_data); + let success_based_connectors = client .calculate_success_rate( tenant_business_profile_id.clone(), success_based_routing_configs.clone(), + success_based_routing_config_params, routable_connectors.clone(), ) .await @@ -956,3 +965,68 @@ pub async fn default_success_based_routing_setup( ); Ok(ApplicationResponse::Json(new_record)) } + +pub fn interpolate_success_based_routing_params( + success_rate_based_config: routing_types::SuccessBasedRoutingConfig, + payment_data: &D, +) -> String +where + F: Send + Clone, + D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, +{ + let mut res = Vec::new(); + for param in success_rate_based_config.params.unwrap() { + let val: String = match param { + routing_types::SuccessBasedRoutingConfigParams::PaymentMethod => payment_data + .get_payment_attempt() + .payment_method + .unwrap() + .to_string(), + routing_types::SuccessBasedRoutingConfigParams::PaymentMethodType => payment_data + .get_payment_attempt() + .get_payment_method_type() + .unwrap() + .to_string(), + routing_types::SuccessBasedRoutingConfigParams::AuthenticationType => payment_data + .get_payment_attempt() + .authentication_type + .unwrap() + .to_string(), + routing_types::SuccessBasedRoutingConfigParams::Currency => { + payment_data.get_currency().to_string() + } + routing_types::SuccessBasedRoutingConfigParams::Country => payment_data + .get_billing_address() + .unwrap() + .address + .unwrap() + .country + .unwrap() + .to_string(), + routing_types::SuccessBasedRoutingConfigParams::CardNetwork => payment_data + .get_payment_attempt() + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_network")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()) + .unwrap(), + routing_types::SuccessBasedRoutingConfigParams::CardBin => payment_data + .get_payment_attempt() + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_number")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()) + .unwrap(), + }; + res.push(val); + } + res.join(":") +} From 3ebeb032deb9329d65c4cd7b538641d27df55692 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 07:25:07 +0000 Subject: [PATCH 07/19] chore: run formatter --- crates/router/src/core/payments/routing.rs | 6 ++++-- crates/router/src/core/routing/helpers.rs | 17 +++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index cef9ac54a3c8..128fda506992 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1301,8 +1301,10 @@ where .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) .attach_printable("unable to fetch success_rate based dynamic routing configs")?; - let success_based_routing_config_params = - interpolate_success_based_routing_params(success_based_routing_configs.clone(), payment_data); + let success_based_routing_config_params = interpolate_success_based_routing_params( + success_based_routing_configs.clone(), + payment_data, + ); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 7225b2a30206..a2355c6caa00 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -28,15 +28,18 @@ use storage_impl::redis::cache; #[cfg(feature = "v2")] use crate::types::domain::MerchantConnectorAccount; +#[cfg(feature = "v1")] +use crate::{core::metrics as core_metrics, routes::metrics, types::transformers::ForeignInto}; use crate::{ - core::{errors::{self, RouterResult}, payments::{OperationSessionGetters, OperationSessionSetters}}, + core::{ + errors::{self, RouterResult}, + payments::{OperationSessionGetters, OperationSessionSetters}, + }, db::StorageInterface, routes::SessionState, types::{domain, storage}, utils::StringExt, }; -#[cfg(feature = "v1")] -use crate::{core::metrics as core_metrics, routes::metrics, types::transformers::ForeignInto}; pub const SUCCESS_BASED_DYNAMIC_ROUTING_ALGORITHM: &str = "Success rate based dynamic routing algorithm"; @@ -645,7 +648,7 @@ pub async fn push_metrics_for_success_based_routing( payment_data: &D, routable_connectors: Vec, business_profile: &domain::Profile, -) -> RouterResult<()> +) -> RouterResult<()> where F: Clone, D: OperationSessionGetters + OperationSessionSetters + Clone, @@ -702,8 +705,10 @@ where business_profile.get_id().get_string_repr(), ); - let success_based_routing_config_params = - interpolate_success_based_routing_params(success_based_routing_configs.clone(), payment_data); + let success_based_routing_config_params = interpolate_success_based_routing_params( + success_based_routing_configs.clone(), + payment_data, + ); let success_based_connectors = client .calculate_success_rate( From 71d2de70fb1bddf08176155abde56312d30b0ffb Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Mon, 4 Nov 2024 13:26:40 +0530 Subject: [PATCH 08/19] add interpolator struct --- crates/router/src/core/payments.rs | 27 +++- .../payments/operations/payment_response.rs | 49 +++++-- crates/router/src/core/payments/routing.rs | 13 +- crates/router/src/core/routing/helpers.rs | 124 +++++++----------- 4 files changed, 116 insertions(+), 97 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index c27e70e1eedc..31013cdf6053 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -73,6 +73,8 @@ use super::{ use crate::core::fraud_check as frm_core; #[cfg(all(feature = "v1", feature = "dynamic_routing"))] use crate::types::api::convert_connector_data_to_routable_connectors; +#[cfg(all(feature = "v1", feature = "dynamic_routing"))] +use crate::core::routing::helpers as routing_helpers; use crate::{ configs::settings::{ApplePayPreDecryptFlow, PaymentMethodTypeTokenFilter}, connector::utils::missing_field_err, @@ -5587,11 +5589,34 @@ where #[cfg(all(feature = "v1", feature = "dynamic_routing"))] let connectors = { if business_profile.dynamic_routing_algorithm.is_some() { + let success_based_routing_config_params_interpolator = routing_helpers::SuccessBasedRoutingConfigParamsInterpolator::new( + payment_data.get_payment_attempt().payment_method, + payment_data.get_payment_attempt().payment_method_type, + payment_data.get_payment_attempt().authentication_type, + payment_data.get_payment_attempt().currency, + payment_data + .get_billing_address() + .unwrap() + .address + .unwrap() + .country, + payment_data + .get_payment_attempt() + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_network")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()), + None, + ); routing::perform_success_based_routing( state, connectors.clone(), business_profile, - payment_data, + success_based_routing_config_params_interpolator, ) .await .map_err(|e| logger::error!(success_rate_routing_error=?e)) diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index fe6a22df9033..09a6202e0c14 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -21,7 +21,7 @@ use tracing_futures::Instrument; use super::{Operation, OperationSessionSetters, PostUpdateTracker}; #[cfg(all(feature = "v1", feature = "dynamic_routing"))] -use crate::core::routing::helpers::push_metrics_for_success_based_routing; +use crate::core::routing::helpers as routing_helpers; use crate::{ connector::utils::PaymentResponseRouterData, consts, @@ -1916,28 +1916,42 @@ async fn payment_response_update_tracker( utils::flatten_join_error(payment_attempt_fut) )?; - payment_data.payment_intent = payment_intent; - payment_data.payment_attempt = payment_attempt; - router_data.payment_method_status.and_then(|status| { - payment_data - .payment_method_info - .as_mut() - .map(|info| info.status = status) - }); - #[cfg(all(feature = "v1", feature = "dynamic_routing"))] { if business_profile.dynamic_routing_algorithm.is_some() { let state = state.clone(); let business_profile = business_profile.clone(); - let payment_data = payment_data.clone(); + let payment_attempt = payment_attempt.clone(); + let success_based_routing_config_params_interpolator = routing_helpers::SuccessBasedRoutingConfigParamsInterpolator::new( + payment_attempt.payment_method, + payment_attempt.payment_method_type, + payment_attempt.authentication_type, + payment_attempt.currency, + payment_data.address.get_payment_billing() + .unwrap() + .address + .clone() + .unwrap() + .country, + payment_attempt + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_network")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()), + None, + ); tokio::spawn( async move { - push_metrics_for_success_based_routing( + routing_helpers::push_metrics_for_success_based_routing( &state, - &payment_data, + &payment_attempt, routable_connectors, &business_profile, + success_based_routing_config_params_interpolator, ) .await .map_err(|e| logger::error!(dynamic_routing_metrics_error=?e)) @@ -1948,6 +1962,15 @@ async fn payment_response_update_tracker( } } + payment_data.payment_intent = payment_intent; + payment_data.payment_attempt = payment_attempt; + router_data.payment_method_status.and_then(|status| { + payment_data + .payment_method_info + .as_mut() + .map(|info| info.status = status) + }); + match router_data.integrity_check { Ok(()) => Ok(payment_data), Err(err) => { diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index cef9ac54a3c8..ec3221486072 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -40,7 +40,6 @@ use rand::{ use rustc_hash::FxHashMap; use storage_impl::redis::cache::{CacheKey, CGRAPH_CACHE, ROUTING_CACHE}; -use super::{OperationSessionGetters, OperationSessionSetters}; #[cfg(feature = "v2")] use crate::core::admin; #[cfg(feature = "payouts")] @@ -1237,18 +1236,13 @@ pub fn make_dsl_input_for_surcharge( /// success based dynamic routing #[cfg(all(feature = "v1", feature = "dynamic_routing"))] -pub async fn perform_success_based_routing( +pub async fn perform_success_based_routing( state: &SessionState, routable_connectors: Vec, business_profile: &domain::Profile, - payment_data: &D, + success_based_routing_config_params_interpolator: routing::helpers::SuccessBasedRoutingConfigParamsInterpolator, ) -> RoutingResult> -where - F: Send + Clone, - D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { - use crate::core::routing::helpers::interpolate_success_based_routing_params; - let success_based_dynamic_routing_algo_ref: api_routing::DynamicRoutingAlgorithmRef = business_profile .dynamic_routing_algorithm @@ -1301,8 +1295,7 @@ where .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) .attach_printable("unable to fetch success_rate based dynamic routing configs")?; - let success_based_routing_config_params = - interpolate_success_based_routing_params(success_based_routing_configs.clone(), payment_data); + let success_based_routing_config_params = success_based_routing_config_params_interpolator.get_string_val(); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 7225b2a30206..0e1af55520c7 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -29,7 +29,7 @@ use storage_impl::redis::cache; #[cfg(feature = "v2")] use crate::types::domain::MerchantConnectorAccount; use crate::{ - core::{errors::{self, RouterResult}, payments::{OperationSessionGetters, OperationSessionSetters}}, + core::errors::{self, RouterResult}, db::StorageInterface, routes::SessionState, types::{domain, storage}, @@ -640,17 +640,14 @@ pub async fn fetch_success_based_routing_configs( /// metrics for success based dynamic routing #[cfg(all(feature = "v1", feature = "dynamic_routing"))] #[instrument(skip_all)] -pub async fn push_metrics_for_success_based_routing( +pub async fn push_metrics_for_success_based_routing( state: &SessionState, - payment_data: &D, + payment_attempt: &storage::PaymentAttempt, routable_connectors: Vec, business_profile: &domain::Profile, + success_based_routing_config_params_interpolator: SuccessBasedRoutingConfigParamsInterpolator, ) -> RouterResult<()> -where - F: Clone, - D: OperationSessionGetters + OperationSessionSetters + Clone, { - let payment_attempt = payment_data.get_payment_attempt(); let success_based_dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef = business_profile .dynamic_routing_algorithm @@ -702,8 +699,7 @@ where business_profile.get_id().get_string_repr(), ); - let success_based_routing_config_params = - interpolate_success_based_routing_params(success_based_routing_configs.clone(), payment_data); + let success_based_routing_config_params = success_based_routing_config_params_interpolator.get_string_val(); let success_based_connectors = client .calculate_success_rate( @@ -734,9 +730,10 @@ where let (first_success_based_connector, merchant_connector_id) = first_success_based_connector_label .split_once(':') .ok_or(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "unable to split connector_name and mca_id from the first connector obtained from dynamic routing service", - )?; + .attach_printable(format!( + "unable to split connector_name and mca_id from the first connector {:?} obtained from dynamic routing service", + first_success_based_connector_label + ))?; let outcome = get_success_based_metrics_outcome_for_payment( &payment_status_attribute, @@ -966,67 +963,48 @@ pub async fn default_success_based_routing_setup( Ok(ApplicationResponse::Json(new_record)) } -pub fn interpolate_success_based_routing_params( - success_rate_based_config: routing_types::SuccessBasedRoutingConfig, - payment_data: &D, -) -> String -where - F: Send + Clone, - D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, -{ - let mut res = Vec::new(); - for param in success_rate_based_config.params.unwrap() { - let val: String = match param { - routing_types::SuccessBasedRoutingConfigParams::PaymentMethod => payment_data - .get_payment_attempt() - .payment_method - .unwrap() - .to_string(), - routing_types::SuccessBasedRoutingConfigParams::PaymentMethodType => payment_data - .get_payment_attempt() - .get_payment_method_type() - .unwrap() - .to_string(), - routing_types::SuccessBasedRoutingConfigParams::AuthenticationType => payment_data - .get_payment_attempt() - .authentication_type - .unwrap() - .to_string(), - routing_types::SuccessBasedRoutingConfigParams::Currency => { - payment_data.get_currency().to_string() +pub struct SuccessBasedRoutingConfigParamsInterpolator { + pub payment_method: Option, + pub payment_method_type: Option, + pub authentication_type: Option, + pub currency: Option, + pub country: Option, + pub card_network: Option, + pub card_bin: Option, +} + +impl SuccessBasedRoutingConfigParamsInterpolator { + pub fn new( + payment_method: Option, + payment_method_type: Option, + authentication_type: Option, + currency: Option, + country: Option, + card_network: Option, + card_bin: Option, + ) -> Self { + SuccessBasedRoutingConfigParamsInterpolator { + payment_method, + payment_method_type, + authentication_type, + currency, + country, + card_network, + card_bin, } - routing_types::SuccessBasedRoutingConfigParams::Country => payment_data - .get_billing_address() - .unwrap() - .address - .unwrap() - .country - .unwrap() - .to_string(), - routing_types::SuccessBasedRoutingConfigParams::CardNetwork => payment_data - .get_payment_attempt() - .payment_method_data - .as_ref() - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card")) - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card_network")) - .and_then(|network| network.as_str()) - .map(|network| network.to_string()) - .unwrap(), - routing_types::SuccessBasedRoutingConfigParams::CardBin => payment_data - .get_payment_attempt() - .payment_method_data - .as_ref() - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card")) - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card_number")) - .and_then(|network| network.as_str()) - .map(|network| network.to_string()) - .unwrap(), - }; - res.push(val); + } + + pub fn get_string_val(&self) -> String { + let parts: Vec = vec![ + self.payment_method.as_ref().map_or(String::new(), |pm| pm.to_string()), + self.payment_method_type.as_ref().map_or(String::new(), |pmt| pmt.to_string()), + self.authentication_type.as_ref().map_or(String::new(), |at| at.to_string()), + self.currency.as_ref().map_or(String::new(), |cur| cur.to_string()), + self.country.as_ref().map_or(String::new(), |cn| cn.to_string()), + self.card_network.clone().unwrap_or_default(), + self.card_bin.clone().unwrap_or_default(), + ]; + + parts.join(":") } - res.join(":") } From 34dbd62bed6c90f98ecefc3f4aa3eaf28ab39875 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 08:00:00 +0000 Subject: [PATCH 09/19] chore: run formatter --- crates/router/src/core/payments.rs | 51 +++++++-------- .../payments/operations/payment_response.rs | 47 +++++++------- crates/router/src/core/payments/routing.rs | 6 +- crates/router/src/core/routing/helpers.rs | 64 +++++++++++-------- 4 files changed, 91 insertions(+), 77 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 31013cdf6053..12ad81937dd8 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -72,9 +72,9 @@ use super::{ #[cfg(feature = "frm")] use crate::core::fraud_check as frm_core; #[cfg(all(feature = "v1", feature = "dynamic_routing"))] -use crate::types::api::convert_connector_data_to_routable_connectors; -#[cfg(all(feature = "v1", feature = "dynamic_routing"))] use crate::core::routing::helpers as routing_helpers; +#[cfg(all(feature = "v1", feature = "dynamic_routing"))] +use crate::types::api::convert_connector_data_to_routable_connectors; use crate::{ configs::settings::{ApplePayPreDecryptFlow, PaymentMethodTypeTokenFilter}, connector::utils::missing_field_err, @@ -5589,29 +5589,30 @@ where #[cfg(all(feature = "v1", feature = "dynamic_routing"))] let connectors = { if business_profile.dynamic_routing_algorithm.is_some() { - let success_based_routing_config_params_interpolator = routing_helpers::SuccessBasedRoutingConfigParamsInterpolator::new( - payment_data.get_payment_attempt().payment_method, - payment_data.get_payment_attempt().payment_method_type, - payment_data.get_payment_attempt().authentication_type, - payment_data.get_payment_attempt().currency, - payment_data - .get_billing_address() - .unwrap() - .address - .unwrap() - .country, - payment_data - .get_payment_attempt() - .payment_method_data - .as_ref() - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card")) - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card_network")) - .and_then(|network| network.as_str()) - .map(|network| network.to_string()), - None, - ); + let success_based_routing_config_params_interpolator = + routing_helpers::SuccessBasedRoutingConfigParamsInterpolator::new( + payment_data.get_payment_attempt().payment_method, + payment_data.get_payment_attempt().payment_method_type, + payment_data.get_payment_attempt().authentication_type, + payment_data.get_payment_attempt().currency, + payment_data + .get_billing_address() + .unwrap() + .address + .unwrap() + .country, + payment_data + .get_payment_attempt() + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_network")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()), + None, + ); routing::perform_success_based_routing( state, connectors.clone(), diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 09a6202e0c14..fd511ac985a9 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1922,28 +1922,31 @@ async fn payment_response_update_tracker( let state = state.clone(); let business_profile = business_profile.clone(); let payment_attempt = payment_attempt.clone(); - let success_based_routing_config_params_interpolator = routing_helpers::SuccessBasedRoutingConfigParamsInterpolator::new( - payment_attempt.payment_method, - payment_attempt.payment_method_type, - payment_attempt.authentication_type, - payment_attempt.currency, - payment_data.address.get_payment_billing() - .unwrap() - .address - .clone() - .unwrap() - .country, - payment_attempt - .payment_method_data - .as_ref() - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card")) - .and_then(|data| data.as_object()) - .and_then(|card| card.get("card_network")) - .and_then(|network| network.as_str()) - .map(|network| network.to_string()), - None, - ); + let success_based_routing_config_params_interpolator = + routing_helpers::SuccessBasedRoutingConfigParamsInterpolator::new( + payment_attempt.payment_method, + payment_attempt.payment_method_type, + payment_attempt.authentication_type, + payment_attempt.currency, + payment_data + .address + .get_payment_billing() + .unwrap() + .address + .clone() + .unwrap() + .country, + payment_attempt + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_network")) + .and_then(|network| network.as_str()) + .map(|network| network.to_string()), + None, + ); tokio::spawn( async move { routing_helpers::push_metrics_for_success_based_routing( diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index ec3221486072..2effc1ed3a69 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1241,8 +1241,7 @@ pub async fn perform_success_based_routing( routable_connectors: Vec, business_profile: &domain::Profile, success_based_routing_config_params_interpolator: routing::helpers::SuccessBasedRoutingConfigParamsInterpolator, -) -> RoutingResult> -{ +) -> RoutingResult> { let success_based_dynamic_routing_algo_ref: api_routing::DynamicRoutingAlgorithmRef = business_profile .dynamic_routing_algorithm @@ -1295,7 +1294,8 @@ pub async fn perform_success_based_routing( .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) .attach_printable("unable to fetch success_rate based dynamic routing configs")?; - let success_based_routing_config_params = success_based_routing_config_params_interpolator.get_string_val(); + let success_based_routing_config_params = + success_based_routing_config_params_interpolator.get_string_val(); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 003c842f59e6..faf7ca6e339d 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -28,8 +28,6 @@ use storage_impl::redis::cache; #[cfg(feature = "v2")] use crate::types::domain::MerchantConnectorAccount; -#[cfg(feature = "v1")] -use crate::{core::metrics as core_metrics, routes::metrics, types::transformers::ForeignInto}; use crate::{ core::errors::{self, RouterResult}, db::StorageInterface, @@ -37,6 +35,8 @@ use crate::{ types::{domain, storage}, utils::StringExt, }; +#[cfg(feature = "v1")] +use crate::{core::metrics as core_metrics, routes::metrics, types::transformers::ForeignInto}; pub const SUCCESS_BASED_DYNAMIC_ROUTING_ALGORITHM: &str = "Success rate based dynamic routing algorithm"; @@ -646,8 +646,7 @@ pub async fn push_metrics_for_success_based_routing( routable_connectors: Vec, business_profile: &domain::Profile, success_based_routing_config_params_interpolator: SuccessBasedRoutingConfigParamsInterpolator, -) -> RouterResult<()> -{ +) -> RouterResult<()> { let success_based_dynamic_routing_algo_ref: routing_types::DynamicRoutingAlgorithmRef = business_profile .dynamic_routing_algorithm @@ -699,7 +698,8 @@ pub async fn push_metrics_for_success_based_routing( business_profile.get_id().get_string_repr(), ); - let success_based_routing_config_params = success_based_routing_config_params_interpolator.get_string_val(); + let success_based_routing_config_params = + success_based_routing_config_params_interpolator.get_string_val(); let success_based_connectors = client .calculate_success_rate( @@ -975,32 +975,42 @@ pub struct SuccessBasedRoutingConfigParamsInterpolator { impl SuccessBasedRoutingConfigParamsInterpolator { pub fn new( - payment_method: Option, - payment_method_type: Option, - authentication_type: Option, - currency: Option, - country: Option, - card_network: Option, - card_bin: Option, - ) -> Self { - SuccessBasedRoutingConfigParamsInterpolator { - payment_method, - payment_method_type, - authentication_type, - currency, - country, - card_network, - card_bin, - } + payment_method: Option, + payment_method_type: Option, + authentication_type: Option, + currency: Option, + country: Option, + card_network: Option, + card_bin: Option, + ) -> Self { + SuccessBasedRoutingConfigParamsInterpolator { + payment_method, + payment_method_type, + authentication_type, + currency, + country, + card_network, + card_bin, } + } pub fn get_string_val(&self) -> String { let parts: Vec = vec![ - self.payment_method.as_ref().map_or(String::new(), |pm| pm.to_string()), - self.payment_method_type.as_ref().map_or(String::new(), |pmt| pmt.to_string()), - self.authentication_type.as_ref().map_or(String::new(), |at| at.to_string()), - self.currency.as_ref().map_or(String::new(), |cur| cur.to_string()), - self.country.as_ref().map_or(String::new(), |cn| cn.to_string()), + self.payment_method + .as_ref() + .map_or(String::new(), |pm| pm.to_string()), + self.payment_method_type + .as_ref() + .map_or(String::new(), |pmt| pmt.to_string()), + self.authentication_type + .as_ref() + .map_or(String::new(), |at| at.to_string()), + self.currency + .as_ref() + .map_or(String::new(), |cur| cur.to_string()), + self.country + .as_ref() + .map_or(String::new(), |cn| cn.to_string()), self.card_network.clone().unwrap_or_default(), self.card_bin.clone().unwrap_or_default(), ]; From 99bd29605b97ee23602af3658aefe5e707cee684 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Tue, 5 Nov 2024 00:05:05 +0530 Subject: [PATCH 10/19] add the changes required for addition of params in redis --- .../src/grpc_client/dynamic_routing.rs | 33 +-------------- crates/router/src/core/payments/routing.rs | 2 +- crates/router/src/core/routing/helpers.rs | 41 +++++++++++++------ 3 files changed, 31 insertions(+), 45 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing.rs b/crates/external_services/src/grpc_client/dynamic_routing.rs index 49fbe5b0a864..596fe7964163 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing.rs @@ -98,6 +98,7 @@ pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync { &self, id: String, success_rate_based_config: SuccessBasedRoutingConfig, + params: String, response: Vec, ) -> DynamicRoutingResult; } @@ -111,21 +112,6 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { params: String, label_input: Vec, ) -> DynamicRoutingResult { - // let params = success_rate_based_config - // .params - // .map(|vec| { - // vec.into_iter().fold(String::new(), |mut acc_str, params| { - // if !acc_str.is_empty() { - // acc_str.push(':') - // } - // acc_str.push_str(params.to_string().as_str()); - // acc_str - // }) - // }) - // .get_required_value("params") - // .change_context(DynamicRoutingError::MissingRequiredField { - // field: "params".to_string(), - // })?; let labels = label_input .into_iter() @@ -161,6 +147,7 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { &self, id: String, success_rate_based_config: SuccessBasedRoutingConfig, + params: String, label_input: Vec, ) -> DynamicRoutingResult { let config = success_rate_based_config @@ -176,22 +163,6 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { }) .collect(); - let params = success_rate_based_config - .params - .map(|vec| { - vec.into_iter().fold(String::new(), |mut acc_str, params| { - if !acc_str.is_empty() { - acc_str.push(':') - } - acc_str.push_str(params.to_string().as_str()); - acc_str - }) - }) - .get_required_value("params") - .change_context(DynamicRoutingError::MissingRequiredField { - field: "params".to_string(), - })?; - let request = tonic::Request::new(UpdateSuccessRateWindowRequest { id, params, diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index ec3221486072..c6f4f14684f5 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1295,7 +1295,7 @@ pub async fn perform_success_based_routing( .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) .attach_printable("unable to fetch success_rate based dynamic routing configs")?; - let success_based_routing_config_params = success_based_routing_config_params_interpolator.get_string_val(); + let success_based_routing_config_params = success_based_routing_config_params_interpolator.get_string_val(success_based_routing_configs.params.as_ref()); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 003c842f59e6..05a574722132 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -699,13 +699,13 @@ pub async fn push_metrics_for_success_based_routing( business_profile.get_id().get_string_repr(), ); - let success_based_routing_config_params = success_based_routing_config_params_interpolator.get_string_val(); + let success_based_routing_config_params = success_based_routing_config_params_interpolator.get_string_val(success_based_routing_configs.params.as_ref()); let success_based_connectors = client .calculate_success_rate( tenant_business_profile_id.clone(), success_based_routing_configs.clone(), - success_based_routing_config_params, + success_based_routing_config_params.clone(), routable_connectors.clone(), ) .await @@ -808,6 +808,7 @@ pub async fn push_metrics_for_success_based_routing( .update_success_rate( tenant_business_profile_id, success_based_routing_configs, + success_based_routing_config_params, vec![routing_types::RoutableConnectorChoiceWithStatus::new( routing_types::RoutableConnectorChoice { choice_kind: api_models::routing::RoutableChoiceKind::FullStruct, @@ -994,17 +995,31 @@ impl SuccessBasedRoutingConfigParamsInterpolator { } } - pub fn get_string_val(&self) -> String { - let parts: Vec = vec![ - self.payment_method.as_ref().map_or(String::new(), |pm| pm.to_string()), - self.payment_method_type.as_ref().map_or(String::new(), |pmt| pmt.to_string()), - self.authentication_type.as_ref().map_or(String::new(), |at| at.to_string()), - self.currency.as_ref().map_or(String::new(), |cur| cur.to_string()), - self.country.as_ref().map_or(String::new(), |cn| cn.to_string()), - self.card_network.clone().unwrap_or_default(), - self.card_bin.clone().unwrap_or_default(), - ]; - + pub fn get_string_val(&self, params: Option<&Vec>) -> String { + let mut parts: Vec = Vec::new(); + if let Some(params) = params { + for param in params { + let val = match param { + routing_types::SuccessBasedRoutingConfigParams::PaymentMethod => + self.payment_method.as_ref().map_or(String::new(), |pm| pm.to_string()), + routing_types::SuccessBasedRoutingConfigParams::PaymentMethodType => + self.payment_method_type.as_ref().map_or(String::new(), |pmt| pmt.to_string()), + routing_types::SuccessBasedRoutingConfigParams::AuthenticationType => + self.authentication_type.as_ref().map_or(String::new(), |at| at.to_string()), + routing_types::SuccessBasedRoutingConfigParams::Currency => + self.currency.as_ref().map_or(String::new(), |cur| cur.to_string()), + routing_types::SuccessBasedRoutingConfigParams::Country => + self.country.as_ref().map_or(String::new(), |cn| cn.to_string()), + routing_types::SuccessBasedRoutingConfigParams::CardNetwork => + self.card_network.clone().unwrap_or_default(), + routing_types::SuccessBasedRoutingConfigParams::CardBin => + self.card_bin.clone().unwrap_or_default(), + }; + if !val.is_empty() { + parts.push(val); + } + } + } parts.join(":") } } From 5763914b616fede5ab33cd3d3356757eb0b2903d Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Tue, 5 Nov 2024 12:54:18 +0530 Subject: [PATCH 11/19] finalize the imp logic --- config/development.toml | 4 ---- crates/router/Cargo.toml | 2 +- crates/router/src/core/payments.rs | 6 ++---- .../src/core/payments/operations/payment_response.rs | 7 ++----- crates/router/src/core/user.rs | 2 +- 5 files changed, 6 insertions(+), 15 deletions(-) diff --git a/config/development.toml b/config/development.toml index 0f33f22d3dd8..d32c36101323 100644 --- a/config/development.toml +++ b/config/development.toml @@ -766,7 +766,3 @@ card_networks = "Visa, AmericanExpress, Mastercard" [network_tokenization_supported_connectors] connector_list = "cybersource" - -[grpc_client.dynamic_routing_client] -host = "localhost" -port = 7000 diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index e197d41b469d..b794443a047f 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true [features] default = ["common_default", "v1"] -common_default = ["dynamic_routing","kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] +common_default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] olap = ["hyperswitch_domain_models/olap", "storage_impl/olap", "scheduler/olap", "api_models/olap", "dep:analytics"] tls = ["actix-web/rustls-0_22"] email = ["external_services/email", "scheduler/email", "olap"] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 12ad81937dd8..902de62172ca 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5597,10 +5597,8 @@ where payment_data.get_payment_attempt().currency, payment_data .get_billing_address() - .unwrap() - .address - .unwrap() - .country, + .and_then(|address| address.address) + .and_then(|address| address.country), payment_data .get_payment_attempt() .payment_method_data diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index fd511ac985a9..94649a0d494a 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1931,11 +1931,8 @@ async fn payment_response_update_tracker( payment_data .address .get_payment_billing() - .unwrap() - .address - .clone() - .unwrap() - .country, + .and_then(|address| address.clone().address) + .and_then(|address| address.country), payment_attempt .payment_method_data .as_ref() diff --git a/crates/router/src/core/user.rs b/crates/router/src/core/user.rs index 822c29b21d99..052b96aadc91 100644 --- a/crates/router/src/core/user.rs +++ b/crates/router/src/core/user.rs @@ -1319,7 +1319,7 @@ pub async fn list_user_roles_details( )) .await .change_context(UserErrors::InternalServerError) - .attach_printable("Failed to construct proifle map")? + .attach_printable("Failed to construct profile map")? .into_iter() .map(|profile| (profile.get_id().to_owned(), profile.profile_name)) .collect::>(); From da893953d51b8672be0c135f1955917d80488300 Mon Sep 17 00:00:00 2001 From: Prajjwal Kumar Date: Tue, 5 Nov 2024 12:56:28 +0530 Subject: [PATCH 12/19] Apply suggestions from code review --- crates/router/src/core/payments/routing.rs | 2 +- crates/router/src/core/routing/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 8555c96b3d5f..1ec939a7dce5 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1295,7 +1295,7 @@ pub async fn perform_success_based_routing( .attach_printable("unable to fetch success_rate based dynamic routing configs")?; let success_based_routing_config_params = success_based_routing_config_params_interpolator - .get_string_val(success_based_routing_configs.params.as_ref()); + .get_string_val(success_based_routing_configs. params.as_ref()); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 773c1ef1d669..252148924936 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -699,7 +699,7 @@ pub async fn push_metrics_for_success_based_routing( ); let success_based_routing_config_params = success_based_routing_config_params_interpolator - .get_string_val(success_based_routing_configs.params.as_ref()); + .get_string_val(success_based_routing_configs. params.as_ref()); let success_based_connectors = client .calculate_success_rate( From a0aaf78e5ae505875a46224cdf44485d12500d1f Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 07:28:01 +0000 Subject: [PATCH 13/19] chore: run formatter --- crates/router/src/core/payments/routing.rs | 2 +- crates/router/src/core/routing/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 1ec939a7dce5..8555c96b3d5f 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1295,7 +1295,7 @@ pub async fn perform_success_based_routing( .attach_printable("unable to fetch success_rate based dynamic routing configs")?; let success_based_routing_config_params = success_based_routing_config_params_interpolator - .get_string_val(success_based_routing_configs. params.as_ref()); + .get_string_val(success_based_routing_configs.params.as_ref()); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 252148924936..773c1ef1d669 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -699,7 +699,7 @@ pub async fn push_metrics_for_success_based_routing( ); let success_based_routing_config_params = success_based_routing_config_params_interpolator - .get_string_val(success_based_routing_configs. params.as_ref()); + .get_string_val(success_based_routing_configs.params.as_ref()); let success_based_connectors = client .calculate_success_rate( From 1517d19dc981a0d0a04b6fdd4f427663333d9a5f Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Tue, 5 Nov 2024 19:13:35 +0530 Subject: [PATCH 14/19] add card_isin --- crates/router/src/core/payments.rs | 11 ++++++++++- .../src/core/payments/operations/payment_response.rs | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 902de62172ca..cd352cdd7601 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5609,7 +5609,16 @@ where .and_then(|card| card.get("card_network")) .and_then(|network| network.as_str()) .map(|network| network.to_string()), - None, + payment_data + .get_payment_attempt() + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_isin")) + .and_then(|card_isin| card_isin.as_str()) + .map(|card_isin| card_isin.to_string()), ); routing::perform_success_based_routing( state, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 94649a0d494a..3aad8039eb8b 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1942,7 +1942,15 @@ async fn payment_response_update_tracker( .and_then(|card| card.get("card_network")) .and_then(|network| network.as_str()) .map(|network| network.to_string()), - None, + payment_attempt + .payment_method_data + .as_ref() + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card")) + .and_then(|data| data.as_object()) + .and_then(|card| card.get("card_isin")) + .and_then(|card_isin| card_isin.as_str()) + .map(|card_isin| card_isin.to_string()), ); tokio::spawn( async move { From df43fe1f89127fbcd738d8b269c2ff3e5313df58 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Tue, 5 Nov 2024 19:47:03 +0530 Subject: [PATCH 15/19] address clippy lints --- crates/router/src/core/routing/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 773c1ef1d669..11c50e259715 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -984,7 +984,7 @@ impl SuccessBasedRoutingConfigParamsInterpolator { card_network: Option, card_bin: Option, ) -> Self { - SuccessBasedRoutingConfigParamsInterpolator { + Self { payment_method, payment_method_type, authentication_type, From 4a2a29aa9f3a70d43c625579e62c216bbfdcabc7 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Wed, 6 Nov 2024 19:35:16 +0530 Subject: [PATCH 16/19] address comments --- crates/external_services/src/grpc_client.rs | 3 - .../src/grpc_client/dynamic_routing.rs | 2 + crates/router/Cargo.toml | 2 +- crates/router/src/core/errors.rs | 2 + .../payments/operations/payment_response.rs | 2 +- crates/router/src/core/payments/routing.rs | 6 +- crates/router/src/core/routing/helpers.rs | 73 ++++++++++--------- 7 files changed, 49 insertions(+), 41 deletions(-) diff --git a/crates/external_services/src/grpc_client.rs b/crates/external_services/src/grpc_client.rs index 5afd30245519..e7b229a80708 100644 --- a/crates/external_services/src/grpc_client.rs +++ b/crates/external_services/src/grpc_client.rs @@ -5,7 +5,6 @@ use std::{fmt::Debug, sync::Arc}; #[cfg(feature = "dynamic_routing")] use dynamic_routing::{DynamicRoutingClientConfig, RoutingStrategy}; -use router_env::logger; use serde; /// Struct contains all the gRPC Clients @@ -38,8 +37,6 @@ impl GrpcClientSettings { .await .expect("Failed to establish a connection with the Dynamic Routing Server"); - logger::info!("Connection established with gRPC Server"); - Arc::new(GrpcClients { #[cfg(feature = "dynamic_routing")] dynamic_routing: dynamic_routing_connection, diff --git a/crates/external_services/src/grpc_client/dynamic_routing.rs b/crates/external_services/src/grpc_client/dynamic_routing.rs index 20239423e189..5ca463771c64 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing.rs @@ -13,6 +13,7 @@ use success_rate::{ CurrentBlockThreshold as DynamicCurrentThreshold, LabelWithStatus, UpdateSuccessRateWindowConfig, UpdateSuccessRateWindowRequest, UpdateSuccessRateWindowResponse, }; +use router_env::logger; use tonic::transport::Channel; #[allow( missing_docs, @@ -72,6 +73,7 @@ impl DynamicRoutingClientConfig { Self::Enabled { host, port } => { let uri = format!("http://{}:{}", host, port); let channel = tonic::transport::Endpoint::new(uri)?.connect().await?; + logger::info!("Connection established with gRPC Server"); Some(SuccessRateCalculatorClient::new(channel)) } Self::Disabled => None, diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index b794443a047f..87f8c7bc43c1 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true [features] default = ["common_default", "v1"] -common_default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] +common_default = ["dynamic_routing", "kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] olap = ["hyperswitch_domain_models/olap", "storage_impl/olap", "scheduler/olap", "api_models/olap", "dep:analytics"] tls = ["actix-web/rustls-0_22"] email = ["external_services/email", "scheduler/email", "olap"] diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index d095b471e2dd..96321d097946 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -330,6 +330,8 @@ pub enum RoutingError { MetadataParsingError, #[error("Unable to retrieve success based routing config")] SuccessBasedRoutingConfigError, + #[error("Params not found in success based routing config")] + SuccessBasedRoutingParamsNotFoundError, #[error("Unable to calculate success based routing config from dynamic routing service")] SuccessRateCalculationError, #[error("Success rate client from dynamic routing gRPC service not initialized")] diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 3aad8039eb8b..cd3247c9b547 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1954,7 +1954,7 @@ async fn payment_response_update_tracker( ); tokio::spawn( async move { - routing_helpers::push_metrics_for_success_based_routing( + routing_helpers::push_metrics_with_update_window_for_success_based_routing( &state, &payment_attempt, routable_connectors, diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 8555c96b3d5f..fecc7b787403 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1295,7 +1295,11 @@ pub async fn perform_success_based_routing( .attach_printable("unable to fetch success_rate based dynamic routing configs")?; let success_based_routing_config_params = success_based_routing_config_params_interpolator - .get_string_val(success_based_routing_configs.params.as_ref()); + .get_string_val( + success_based_routing_configs + .params.as_ref() + .ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError) + .attach_printable("params not found in success based routing config")?); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 11c50e259715..7bde55a0d2af 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -640,7 +640,7 @@ pub async fn fetch_success_based_routing_configs( /// metrics for success based dynamic routing #[cfg(all(feature = "v1", feature = "dynamic_routing"))] #[instrument(skip_all)] -pub async fn push_metrics_for_success_based_routing( +pub async fn push_metrics_with_update_window_for_success_based_routing( state: &SessionState, payment_attempt: &storage::PaymentAttempt, routable_connectors: Vec, @@ -699,7 +699,12 @@ pub async fn push_metrics_for_success_based_routing( ); let success_based_routing_config_params = success_based_routing_config_params_interpolator - .get_string_val(success_based_routing_configs.params.as_ref()); + .get_string_val( + success_based_routing_configs + .params.as_ref() + .ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("params not found in success based routing config")?); let success_based_connectors = client .calculate_success_rate( @@ -997,42 +1002,40 @@ impl SuccessBasedRoutingConfigParamsInterpolator { pub fn get_string_val( &self, - params: Option<&Vec>, + params: &Vec, ) -> String { let mut parts: Vec = Vec::new(); - if let Some(params) = params { - for param in params { - let val = match param { - routing_types::SuccessBasedRoutingConfigParams::PaymentMethod => self - .payment_method - .as_ref() - .map_or(String::new(), |pm| pm.to_string()), - routing_types::SuccessBasedRoutingConfigParams::PaymentMethodType => self - .payment_method_type - .as_ref() - .map_or(String::new(), |pmt| pmt.to_string()), - routing_types::SuccessBasedRoutingConfigParams::AuthenticationType => self - .authentication_type - .as_ref() - .map_or(String::new(), |at| at.to_string()), - routing_types::SuccessBasedRoutingConfigParams::Currency => self - .currency - .as_ref() - .map_or(String::new(), |cur| cur.to_string()), - routing_types::SuccessBasedRoutingConfigParams::Country => self - .country - .as_ref() - .map_or(String::new(), |cn| cn.to_string()), - routing_types::SuccessBasedRoutingConfigParams::CardNetwork => { - self.card_network.clone().unwrap_or_default() - } - routing_types::SuccessBasedRoutingConfigParams::CardBin => { - self.card_bin.clone().unwrap_or_default() - } - }; - if !val.is_empty() { - parts.push(val); + for param in params { + let val = match param { + routing_types::SuccessBasedRoutingConfigParams::PaymentMethod => self + .payment_method + .as_ref() + .map_or(String::new(), |pm| pm.to_string()), + routing_types::SuccessBasedRoutingConfigParams::PaymentMethodType => self + .payment_method_type + .as_ref() + .map_or(String::new(), |pmt| pmt.to_string()), + routing_types::SuccessBasedRoutingConfigParams::AuthenticationType => self + .authentication_type + .as_ref() + .map_or(String::new(), |at| at.to_string()), + routing_types::SuccessBasedRoutingConfigParams::Currency => self + .currency + .as_ref() + .map_or(String::new(), |cur| cur.to_string()), + routing_types::SuccessBasedRoutingConfigParams::Country => self + .country + .as_ref() + .map_or(String::new(), |cn| cn.to_string()), + routing_types::SuccessBasedRoutingConfigParams::CardNetwork => { + self.card_network.clone().unwrap_or_default() + } + routing_types::SuccessBasedRoutingConfigParams::CardBin => { + self.card_bin.clone().unwrap_or_default() } + }; + if !val.is_empty() { + parts.push(val); } } parts.join(":") From 32e47453876e353d9060571a64d1a790656eed80 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Thu, 7 Nov 2024 08:04:24 +0530 Subject: [PATCH 17/19] remove cargo changes --- crates/router/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 87f8c7bc43c1..b794443a047f 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true [features] default = ["common_default", "v1"] -common_default = ["dynamic_routing", "kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] +common_default = ["kv_store", "stripe", "oltp", "olap", "accounts_cache", "dummy_connector", "payouts", "payout_retry", "retry", "frm", "tls", "partial-auth", "km_forward_x_request_id"] olap = ["hyperswitch_domain_models/olap", "storage_impl/olap", "scheduler/olap", "api_models/olap", "dep:analytics"] tls = ["actix-web/rustls-0_22"] email = ["external_services/email", "scheduler/email", "olap"] From 8461afd87a26fb9a7059101c0371c432020ada3c Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 7 Nov 2024 03:38:30 +0000 Subject: [PATCH 18/19] chore: run formatter --- crates/external_services/src/grpc_client/dynamic_routing.rs | 2 +- crates/router/src/core/payments/routing.rs | 6 ++++-- crates/router/src/core/routing/helpers.rs | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing.rs b/crates/external_services/src/grpc_client/dynamic_routing.rs index a50f89764642..2e467f3f4ae1 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing.rs @@ -9,6 +9,7 @@ use error_stack::ResultExt; use http_body_util::combinators::UnsyncBoxBody; use hyper::body::Bytes; use hyper_util::client::legacy::connect::HttpConnector; +use router_env::logger; use serde; use success_rate::{ success_rate_calculator_client::SuccessRateCalculatorClient, CalSuccessRateConfig, @@ -16,7 +17,6 @@ use success_rate::{ CurrentBlockThreshold as DynamicCurrentThreshold, LabelWithStatus, UpdateSuccessRateWindowConfig, UpdateSuccessRateWindowRequest, UpdateSuccessRateWindowResponse, }; -use router_env::logger; use tonic::Status; #[allow( missing_docs, diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index fecc7b787403..3d91605a44a2 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1297,9 +1297,11 @@ pub async fn perform_success_based_routing( let success_based_routing_config_params = success_based_routing_config_params_interpolator .get_string_val( success_based_routing_configs - .params.as_ref() + .params + .as_ref() .ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError) - .attach_printable("params not found in success based routing config")?); + .attach_printable("params not found in success based routing config")?, + ); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index ce82f5fa3ba6..a0dd2ed1c688 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -701,10 +701,12 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( let success_based_routing_config_params = success_based_routing_config_params_interpolator .get_string_val( success_based_routing_configs - .params.as_ref() + .params + .as_ref() .ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError) .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("params not found in success based routing config")?); + .attach_printable("params not found in success based routing config")?, + ); let success_based_connectors = client .calculate_success_rate( From 71c345e855e7937ecff8f57be2ada2998daddd65 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Thu, 7 Nov 2024 17:14:36 +0530 Subject: [PATCH 19/19] address nit comments --- crates/external_services/src/grpc_client/dynamic_routing.rs | 2 +- crates/router/src/core/payments/routing.rs | 3 +-- crates/router/src/core/routing/helpers.rs | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing.rs b/crates/external_services/src/grpc_client/dynamic_routing.rs index 2e467f3f4ae1..0546d05ba7c9 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing.rs @@ -81,7 +81,7 @@ impl DynamicRoutingClientConfig { let success_rate_client = match self { Self::Enabled { host, port } => { let uri = format!("http://{}:{}", host, port).parse::()?; - logger::info!("Connection established with gRPC Server"); + logger::info!("Connection established with dynamic routing gRPC Server"); Some(SuccessRateCalculatorClient::with_origin(client, uri)) } Self::Disabled => None, diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 3d91605a44a2..28321529ef2d 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1299,8 +1299,7 @@ pub async fn perform_success_based_routing( success_based_routing_configs .params .as_ref() - .ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError) - .attach_printable("params not found in success based routing config")?, + .ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError)?, ); let tenant_business_profile_id = routing::helpers::generate_tenant_business_profile_id( diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index a0dd2ed1c688..0250d00d1bbc 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -704,8 +704,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( .params .as_ref() .ok_or(errors::RoutingError::SuccessBasedRoutingParamsNotFoundError) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("params not found in success based routing config")?, + .change_context(errors::ApiErrorResponse::InternalServerError)?, ); let success_based_connectors = client