From c07692011d348d63f20f7893778ff1c8b69f67b8 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 26 Dec 2024 19:15:40 +0530 Subject: [PATCH 01/17] feat(routing): Integrate global success rates --- crates/api_models/src/routing.rs | 12 ++++++ .../dynamic_routing/success_rate_client.rs | 19 ++++++--- crates/router/src/core/payments/routing.rs | 38 +++++++++-------- crates/router/src/core/routing/helpers.rs | 42 +++++++++++++++---- proto/success_rate.proto | 14 ++++++- 5 files changed, 92 insertions(+), 33 deletions(-) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 2e570816ab4c..5c0efbb242c1 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -779,6 +779,7 @@ impl Default for SuccessBasedRoutingConfig { duration_in_mins: Some(5), max_total_count: Some(2), }), + specificity_level: Some(SuccessRateSpecificityLevel::default()), }), } } @@ -801,6 +802,7 @@ pub struct SuccessBasedRoutingConfigBody { pub default_success_rate: Option, pub max_aggregates_size: Option, pub current_block_threshold: Option, + pub specificity_level: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema)] @@ -809,6 +811,13 @@ pub struct CurrentBlockThreshold { pub max_total_count: Option, } +#[derive(serde::Serialize, serde::Deserialize, Debug, Default, Clone, ToSchema)] +pub enum SuccessRateSpecificityLevel { + #[default] + Merchant, + Global, +} + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct SuccessBasedRoutingPayloadWrapper { pub updated_config: SuccessBasedRoutingConfig, @@ -849,6 +858,9 @@ impl SuccessBasedRoutingConfigBody { .as_mut() .map(|threshold| threshold.update(current_block_threshold)); } + if let Some(level) = new.specificity_level { + self.specificity_level = Some(level) + } } } diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index 3cf06ab63beb..e6e80ed28680 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -1,14 +1,15 @@ use api_models::routing::{ CurrentBlockThreshold, RoutableConnectorChoice, RoutableConnectorChoiceWithStatus, - SuccessBasedRoutingConfig, SuccessBasedRoutingConfigBody, + SuccessBasedRoutingConfig, SuccessBasedRoutingConfigBody, SuccessRateSpecificityLevel, }; use common_utils::{ext_traits::OptionExt, transformers::ForeignTryFrom}; use error_stack::ResultExt; pub use success_rate::{ - success_rate_calculator_client::SuccessRateCalculatorClient, CalSuccessRateConfig, - CalSuccessRateRequest, CalSuccessRateResponse, - CurrentBlockThreshold as DynamicCurrentThreshold, InvalidateWindowsRequest, - InvalidateWindowsResponse, LabelWithStatus, UpdateSuccessRateWindowConfig, + success_rate_calculator_client::SuccessRateCalculatorClient, + success_rate_specificity_level::SpecificityLevel, CalSuccessRateConfig, CalSuccessRateRequest, + CalSuccessRateResponse, CurrentBlockThreshold as DynamicCurrentThreshold, + InvalidateWindowsRequest, InvalidateWindowsResponse, LabelWithStatus, + SuccessRateSpecificityLevel as ProtoSpecificityLevel, UpdateSuccessRateWindowConfig, UpdateSuccessRateWindowRequest, UpdateSuccessRateWindowResponse, }; #[allow( @@ -203,6 +204,14 @@ impl ForeignTryFrom for CalSuccessRateConfig { .change_context(DynamicRoutingError::MissingRequiredField { field: "default_success_rate".to_string(), })?, + specificity_level: config.specificity_level.map(|level| match level { + SuccessRateSpecificityLevel::Merchant => ProtoSpecificityLevel { + status: SpecificityLevel::Merchant.into(), + }, + SuccessRateSpecificityLevel::Global => ProtoSpecificityLevel { + status: SpecificityLevel::Global.into(), + }, + }), }) } } diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 0a57819816fb..b1aaa8c1149e 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1322,22 +1322,23 @@ pub async fn perform_success_based_routing( .ok_or(errors::RoutingError::SuccessRateClientInitializationError) .attach_printable("success_rate gRPC client not found")?; - let success_based_routing_configs = routing::helpers::fetch_success_based_routing_configs( - state, - business_profile, - success_based_algo_ref - .algorithm_id_with_timestamp - .algorithm_id - .ok_or(errors::RoutingError::GenericNotFoundError { - field: "success_based_routing_algorithm_id".to_string(), - }) - .attach_printable( - "success_based_routing_algorithm_id not found in business_profile", - )?, - ) - .await - .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) - .attach_printable("unable to fetch success_rate based dynamic routing configs")?; + let success_based_routing_configs = + routing::helpers::fetch_success_based_routing_configs( + state, + business_profile, + success_based_algo_ref + .algorithm_id_with_timestamp + .algorithm_id + .ok_or(errors::RoutingError::GenericNotFoundError { + field: "success_based_routing_algorithm_id".to_string(), + }) + .attach_printable( + "success_based_routing_algorithm_id not found in business_profile", + )?, + ) + .await + .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( @@ -1366,8 +1367,9 @@ pub async fn perform_success_based_routing( "unable to calculate/fetch success rate from dynamic routing service", )?; - let mut connectors = Vec::with_capacity(success_based_connectors.labels_with_score.len()); - for label_with_score in success_based_connectors.labels_with_score { + let mut connectors = + Vec::with_capacity(success_based_connectors.merchant_labels_with_score.len()); + for label_with_score in success_based_connectors.merchant_labels_with_score { let (connector, merchant_connector_id) = label_with_score.label .split_once(':') .ok_or(errors::RoutingError::InvalidSuccessBasedConnectorLabel(label_with_score.label.to_string())) diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 489c3122a8e9..28d3952c420a 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -699,6 +699,10 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to retrieve success_rate based dynamic routing configs")?; + success_based_routing_configs.config.as_mut().map(|config| { + config.specificity_level = Some(routing_types::SuccessRateSpecificityLevel::Global) + }); + let tenant_business_profile_id = generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, business_profile.get_id().get_string_repr(), @@ -730,8 +734,8 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( let payment_status_attribute = get_desired_payment_status_for_success_routing_metrics(payment_attempt.status); - let first_success_based_connector_label = &success_based_connectors - .labels_with_score + let first_merchant_success_based_connector_label = &success_based_connectors + .merchant_labels_with_score .first() .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable( @@ -740,18 +744,36 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( .label .to_string(); - let (first_success_based_connector, _) = first_success_based_connector_label + let (first_merchant_success_based_connector, _) = first_merchant_success_based_connector_label .split_once(':') .ok_or(errors::ApiErrorResponse::InternalServerError) .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 + first_merchant_success_based_connector_label + ))?; + + let first_global_success_based_connector_label = &success_based_connectors + .global_labels_with_score + .first() + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "unable to fetch the first connector from list of connectors obtained from dynamic routing service", + )? + .label + .to_string(); + + let (first_global_success_based_connector, _) = first_global_success_based_connector_label + .split_once(':') + .ok_or(errors::ApiErrorResponse::InternalServerError) + .attach_printable(format!( + "unable to split connector_name and mca_id from the first connector {:?} obtained from dynamic routing service", + first_global_success_based_connector_label ))?; let outcome = get_success_based_metrics_outcome_for_payment( payment_status_attribute, payment_connector.to_string(), - first_success_based_connector.to_string(), + first_merchant_success_based_connector.to_string(), ); let dynamic_routing_stats = DynamicRoutingStatsNew { @@ -760,7 +782,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( merchant_id: payment_attempt.merchant_id.to_owned(), profile_id: payment_attempt.profile_id.to_owned(), amount: payment_attempt.get_total_amount(), - success_based_routing_connector: first_success_based_connector.to_string(), + success_based_routing_connector: first_merchant_success_based_connector.to_string(), payment_connector: payment_connector.to_string(), payment_method_type: payment_attempt.payment_method_type, currency: payment_attempt.currency, @@ -788,8 +810,12 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( ), ), ( - "success_based_routing_connector", - first_success_based_connector.to_string(), + "merchant_specific_success_based_routing_connector", + first_merchant_success_based_connector.to_string(), + ), + ( + "global_success_based_routing_connector", + first_global_success_based_connector.to_string(), ), ("payment_connector", payment_connector.to_string()), ( diff --git a/proto/success_rate.proto b/proto/success_rate.proto index 38e56e36c0ff..8eae21f41bce 100644 --- a/proto/success_rate.proto +++ b/proto/success_rate.proto @@ -20,10 +20,20 @@ message CalSuccessRateRequest { message CalSuccessRateConfig { uint32 min_aggregates_size = 1; double default_success_rate = 2; + SuccessRateSpecificityLevel specificity_level = 3; +} + +message SuccessRateSpecificityLevel { + enum SpecificityLevel { + MERCHANT = 0; + GLOBAL = 1; + } + SpecificityLevel status = 1; } message CalSuccessRateResponse { - repeated LabelWithScore labels_with_score = 1; + repeated LabelWithScore merchant_labels_with_score = 1; + repeated LabelWithScore global_labels_with_score = 2; } message LabelWithScore { @@ -31,7 +41,7 @@ message LabelWithScore { string label = 2; } - // API-2 types +// API-2 types message UpdateSuccessRateWindowRequest { string id = 1; string params = 2; From 729fe38179fdd27a1573da8e9a8ac6324b2f4290 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:47:26 +0000 Subject: [PATCH 02/17] chore: run formatter --- crates/router/src/core/payments/routing.rs | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index b1aaa8c1149e..cbb6ef934135 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1322,23 +1322,22 @@ pub async fn perform_success_based_routing( .ok_or(errors::RoutingError::SuccessRateClientInitializationError) .attach_printable("success_rate gRPC client not found")?; - let success_based_routing_configs = - routing::helpers::fetch_success_based_routing_configs( - state, - business_profile, - success_based_algo_ref - .algorithm_id_with_timestamp - .algorithm_id - .ok_or(errors::RoutingError::GenericNotFoundError { - field: "success_based_routing_algorithm_id".to_string(), - }) - .attach_printable( - "success_based_routing_algorithm_id not found in business_profile", - )?, - ) - .await - .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) - .attach_printable("unable to fetch success_rate based dynamic routing configs")?; + let success_based_routing_configs = routing::helpers::fetch_success_based_routing_configs( + state, + business_profile, + success_based_algo_ref + .algorithm_id_with_timestamp + .algorithm_id + .ok_or(errors::RoutingError::GenericNotFoundError { + field: "success_based_routing_algorithm_id".to_string(), + }) + .attach_printable( + "success_based_routing_algorithm_id not found in business_profile", + )?, + ) + .await + .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( From d48243ff6064af73502fa1ea355053bded48b756 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 26 Dec 2024 19:51:41 +0530 Subject: [PATCH 03/17] fix: Fixed errors --- .../src/grpc_client/dynamic_routing/success_rate_client.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index e6e80ed28680..d212b3bc75b8 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -16,7 +16,8 @@ pub use success_rate::{ missing_docs, unused_qualifications, clippy::unwrap_used, - clippy::as_conversions + clippy::as_conversions, + clippy::use_self )] pub mod success_rate { tonic::include_proto!("success_rate"); From 1d659393d0da5e61d4a067aa8151981361da0f55 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 26 Dec 2024 22:07:26 +0530 Subject: [PATCH 04/17] fix: Fixed errors --- 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 28d3952c420a..314444cabb49 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -684,7 +684,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( }, )?; - let success_based_routing_configs = fetch_success_based_routing_configs( + let mut success_based_routing_configs = fetch_success_based_routing_configs( state, business_profile, success_based_algo_ref From 9b53e883282894865f8232e317b5ebc8ef54b94f Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Sat, 28 Dec 2024 02:05:37 +0530 Subject: [PATCH 05/17] reafctor: proto file restructuring --- .../dynamic_routing/success_rate_client.rs | 65 ++++++++++++++++--- crates/router/src/core/routing/helpers.rs | 6 +- proto/success_rate.proto | 34 +++++++--- 3 files changed, 83 insertions(+), 22 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index d212b3bc75b8..8b124211af50 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -5,10 +5,11 @@ use api_models::routing::{ use common_utils::{ext_traits::OptionExt, transformers::ForeignTryFrom}; use error_stack::ResultExt; pub use success_rate::{ - success_rate_calculator_client::SuccessRateCalculatorClient, - success_rate_specificity_level::SpecificityLevel, CalSuccessRateConfig, CalSuccessRateRequest, - CalSuccessRateResponse, CurrentBlockThreshold as DynamicCurrentThreshold, - InvalidateWindowsRequest, InvalidateWindowsResponse, LabelWithStatus, + success_rate_calculator_client::SuccessRateCalculatorClient, CalGlobalSuccessRateConfig, + CalGlobalSuccessRateRequest, CalGlobalSuccessRateResponse, CalSuccessRateConfig, + CalSuccessRateRequest, CalSuccessRateResponse, + CurrentBlockThreshold as DynamicCurrentThreshold, InvalidateWindowsRequest, + InvalidateWindowsResponse, LabelWithStatus, SuccessRateSpecificityLevel as ProtoSpecificityLevel, UpdateSuccessRateWindowConfig, UpdateSuccessRateWindowRequest, UpdateSuccessRateWindowResponse, }; @@ -51,6 +52,15 @@ pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync { id: String, headers: GrpcHeaders, ) -> DynamicRoutingResult; + /// To calculate both global and merchant specific success rate for the list of chosen connectors + async fn calculate_global_success_rate( + &self, + id: String, + success_rate_based_config: SuccessBasedRoutingConfig, + params: String, + label_input: Vec, + headers: GrpcHeaders, + ) -> DynamicRoutingResult; } #[async_trait::async_trait] @@ -154,6 +164,45 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { .into_inner(); Ok(response) } + + async fn calculate_global_success_rate( + &self, + id: String, + success_rate_based_config: SuccessBasedRoutingConfig, + params: String, + label_input: Vec, + headers: GrpcHeaders, + ) -> DynamicRoutingResult { + let labels = label_input + .into_iter() + .map(|conn_choice| conn_choice.to_string()) + .collect::>(); + + let config = success_rate_based_config + .config + .map(ForeignTryFrom::foreign_try_from) + .transpose()?; + + let mut request = tonic::Request::new(CalGlobalSuccessRateRequest { + id, + params, + labels, + config, + }); + + request.add_headers_to_grpc_request(headers); + + let response = self + .clone() + .fetch_entity_and_global_success_rate(request) + .await + .change_context(DynamicRoutingError::SuccessRateBasedRoutingFailure( + "Failed to fetch the success rate".to_string(), + ))? + .into_inner(); + + Ok(response) + } } impl ForeignTryFrom for DynamicCurrentThreshold { @@ -206,12 +255,8 @@ impl ForeignTryFrom for CalSuccessRateConfig { field: "default_success_rate".to_string(), })?, specificity_level: config.specificity_level.map(|level| match level { - SuccessRateSpecificityLevel::Merchant => ProtoSpecificityLevel { - status: SpecificityLevel::Merchant.into(), - }, - SuccessRateSpecificityLevel::Global => ProtoSpecificityLevel { - status: SpecificityLevel::Global.into(), - }, + SuccessRateSpecificityLevel::Merchant => ProtoSpecificityLevel::Entity, + SuccessRateSpecificityLevel::Global => ProtoSpecificityLevel::Global, }), }) } diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 314444cabb49..e0de6e5aa673 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -718,7 +718,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( ); let success_based_connectors = client - .calculate_success_rate( + .calculate_global_success_rate( tenant_business_profile_id.clone(), success_based_routing_configs.clone(), success_based_routing_config_params.clone(), @@ -735,7 +735,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( get_desired_payment_status_for_success_routing_metrics(payment_attempt.status); let first_merchant_success_based_connector_label = &success_based_connectors - .merchant_labels_with_score + .entity_scores_with_labels .first() .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable( @@ -753,7 +753,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( ))?; let first_global_success_based_connector_label = &success_based_connectors - .global_labels_with_score + .global_scores_with_labels .first() .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable( diff --git a/proto/success_rate.proto b/proto/success_rate.proto index 8eae21f41bce..bd990049b730 100644 --- a/proto/success_rate.proto +++ b/proto/success_rate.proto @@ -7,6 +7,8 @@ service SuccessRateCalculator { rpc UpdateSuccessRateWindow (UpdateSuccessRateWindowRequest) returns (UpdateSuccessRateWindowResponse); rpc InvalidateWindows (InvalidateWindowsRequest) returns (InvalidateWindowsResponse); + + rpc FetchEntityAndGlobalSuccessRate (CalGlobalSuccessRateRequest) returns (CalGlobalSuccessRateResponse); } // API-1 types @@ -20,20 +22,16 @@ message CalSuccessRateRequest { message CalSuccessRateConfig { uint32 min_aggregates_size = 1; double default_success_rate = 2; - SuccessRateSpecificityLevel specificity_level = 3; + optional SuccessRateSpecificityLevel specificity_level = 3; } -message SuccessRateSpecificityLevel { - enum SpecificityLevel { - MERCHANT = 0; - GLOBAL = 1; - } - SpecificityLevel status = 1; +enum SuccessRateSpecificityLevel { + ENTITY = 0; + GLOBAL = 1; } message CalSuccessRateResponse { - repeated LabelWithScore merchant_labels_with_score = 1; - repeated LabelWithScore global_labels_with_score = 2; + repeated LabelWithScore labels_with_score = 1; } message LabelWithScore { @@ -75,4 +73,22 @@ message InvalidateWindowsRequest { message InvalidateWindowsResponse { string message = 1; +} + +// API-4 types +message CalGlobalSuccessRateRequest { + string id = 1; + string params = 2; + repeated string labels = 3; + CalGlobalSuccessRateConfig config = 4; +} + +message CalGlobalSuccessRateConfig { + uint32 entity_min_aggregates_size = 1; + double entity_default_success_rate = 2; +} + +message CalGlobalSuccessRateResponse { + repeated LabelWithScore entity_scores_with_labels = 1; + repeated LabelWithScore global_scores_with_labels = 2; } \ No newline at end of file From 6bb17eb9b3f81c2a5b746e5f1331231728b2a356 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Sat, 28 Dec 2024 02:27:12 +0530 Subject: [PATCH 06/17] fix: Fixed errors --- .../dynamic_routing/success_rate_client.rs | 24 ++++++++++- crates/router/src/core/payments/routing.rs | 43 +++++++++++-------- crates/router/src/core/routing/helpers.rs | 6 +-- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index 8b124211af50..7e01cde3b463 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -255,9 +255,29 @@ impl ForeignTryFrom for CalSuccessRateConfig { field: "default_success_rate".to_string(), })?, specificity_level: config.specificity_level.map(|level| match level { - SuccessRateSpecificityLevel::Merchant => ProtoSpecificityLevel::Entity, - SuccessRateSpecificityLevel::Global => ProtoSpecificityLevel::Global, + SuccessRateSpecificityLevel::Merchant => ProtoSpecificityLevel::Entity.into(), + SuccessRateSpecificityLevel::Global => ProtoSpecificityLevel::Global.into(), }), }) } } + +impl ForeignTryFrom for CalGlobalSuccessRateConfig { + type Error = error_stack::Report; + fn foreign_try_from(config: SuccessBasedRoutingConfigBody) -> Result { + Ok(Self { + entity_min_aggregates_size: config + .min_aggregates_size + .get_required_value("min_aggregate_size") + .change_context(DynamicRoutingError::MissingRequiredField { + field: "min_aggregates_size".to_string(), + })?, + entity_default_success_rate: config + .default_success_rate + .get_required_value("default_success_rate") + .change_context(DynamicRoutingError::MissingRequiredField { + field: "default_success_rate".to_string(), + })?, + }) + } +} diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index cbb6ef934135..09037983c91f 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1322,22 +1322,28 @@ pub async fn perform_success_based_routing( .ok_or(errors::RoutingError::SuccessRateClientInitializationError) .attach_printable("success_rate gRPC client not found")?; - let success_based_routing_configs = routing::helpers::fetch_success_based_routing_configs( - state, - business_profile, - success_based_algo_ref - .algorithm_id_with_timestamp - .algorithm_id - .ok_or(errors::RoutingError::GenericNotFoundError { - field: "success_based_routing_algorithm_id".to_string(), - }) - .attach_printable( - "success_based_routing_algorithm_id not found in business_profile", - )?, - ) - .await - .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) - .attach_printable("unable to fetch success_rate based dynamic routing configs")?; + let mut success_based_routing_configs = + routing::helpers::fetch_success_based_routing_configs( + state, + business_profile, + success_based_algo_ref + .algorithm_id_with_timestamp + .algorithm_id + .ok_or(errors::RoutingError::GenericNotFoundError { + field: "success_based_routing_algorithm_id".to_string(), + }) + .attach_printable( + "success_based_routing_algorithm_id not found in business_profile", + )?, + ) + .await + .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) + .attach_printable("unable to fetch success_rate based dynamic routing configs")?; + + success_based_routing_configs.config.as_mut().map(|config| { + config.specificity_level = + Some(api_models::routing::SuccessRateSpecificityLevel::Merchant) + }); let success_based_routing_config_params = success_based_routing_config_params_interpolator .get_string_val( @@ -1366,9 +1372,8 @@ pub async fn perform_success_based_routing( "unable to calculate/fetch success rate from dynamic routing service", )?; - let mut connectors = - Vec::with_capacity(success_based_connectors.merchant_labels_with_score.len()); - for label_with_score in success_based_connectors.merchant_labels_with_score { + let mut connectors = Vec::with_capacity(success_based_connectors.labels_with_score.len()); + for label_with_score in success_based_connectors.labels_with_score { let (connector, merchant_connector_id) = label_with_score.label .split_once(':') .ok_or(errors::RoutingError::InvalidSuccessBasedConnectorLabel(label_with_score.label.to_string())) diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index e0de6e5aa673..e0cf2dc73faf 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -684,7 +684,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( }, )?; - let mut success_based_routing_configs = fetch_success_based_routing_configs( + let success_based_routing_configs = fetch_success_based_routing_configs( state, business_profile, success_based_algo_ref @@ -699,10 +699,6 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("unable to retrieve success_rate based dynamic routing configs")?; - success_based_routing_configs.config.as_mut().map(|config| { - config.specificity_level = Some(routing_types::SuccessRateSpecificityLevel::Global) - }); - let tenant_business_profile_id = generate_tenant_business_profile_id( &state.tenant.redis_key_prefix, business_profile.get_id().get_string_repr(), From 6f47024eeaf39415b69b0bfa00d97f1061ca975c Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 2 Jan 2025 17:16:48 +0530 Subject: [PATCH 07/17] chore: Resolved comments --- crates/api_models/src/routing.rs | 10 +++---- .../dynamic_routing/success_rate_client.rs | 29 ++++++++++++------- crates/openapi/src/openapi.rs | 1 + crates/router/src/core/payments/routing.rs | 5 ---- crates/router/src/core/routing/helpers.rs | 26 +++++++---------- proto/success_rate.proto | 11 ++++--- 6 files changed, 42 insertions(+), 40 deletions(-) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 5c0efbb242c1..8e5027675753 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -779,7 +779,7 @@ impl Default for SuccessBasedRoutingConfig { duration_in_mins: Some(5), max_total_count: Some(2), }), - specificity_level: Some(SuccessRateSpecificityLevel::default()), + specificity_level: SuccessRateSpecificityLevel::default(), }), } } @@ -802,7 +802,8 @@ pub struct SuccessBasedRoutingConfigBody { pub default_success_rate: Option, pub max_aggregates_size: Option, pub current_block_threshold: Option, - pub specificity_level: Option, + #[serde(default)] + pub specificity_level: SuccessRateSpecificityLevel, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema)] @@ -812,6 +813,7 @@ pub struct CurrentBlockThreshold { } #[derive(serde::Serialize, serde::Deserialize, Debug, Default, Clone, ToSchema)] +#[serde(rename_all = "snake_case")] pub enum SuccessRateSpecificityLevel { #[default] Merchant, @@ -858,9 +860,7 @@ impl SuccessBasedRoutingConfigBody { .as_mut() .map(|threshold| threshold.update(current_block_threshold)); } - if let Some(level) = new.specificity_level { - self.specificity_level = Some(level) - } + self.specificity_level = new.specificity_level } } diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index 7e01cde3b463..f3676802da6e 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -53,7 +53,7 @@ pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync { headers: GrpcHeaders, ) -> DynamicRoutingResult; /// To calculate both global and merchant specific success rate for the list of chosen connectors - async fn calculate_global_success_rate( + async fn calculate_entity_and_global_success_rate( &self, id: String, success_rate_based_config: SuccessBasedRoutingConfig, @@ -165,7 +165,7 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { Ok(response) } - async fn calculate_global_success_rate( + async fn calculate_entity_and_global_success_rate( &self, id: String, success_rate_based_config: SuccessBasedRoutingConfig, @@ -174,19 +174,28 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { headers: GrpcHeaders, ) -> DynamicRoutingResult { let labels = label_input + .clone() .into_iter() .map(|conn_choice| conn_choice.to_string()) .collect::>(); + let global_labels = label_input + .into_iter() + .map(|conn_choice| conn_choice.connector.to_string()) + .collect::>(); + let config = success_rate_based_config .config .map(ForeignTryFrom::foreign_try_from) .transpose()?; let mut request = tonic::Request::new(CalGlobalSuccessRateRequest { - id, - params, - labels, + entity_id: id, + entity_params: params.clone(), + entity_labels: labels, + global_id: "".to_string(), + global_params: params, + global_labels, config, }); @@ -197,7 +206,7 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { .fetch_entity_and_global_success_rate(request) .await .change_context(DynamicRoutingError::SuccessRateBasedRoutingFailure( - "Failed to fetch the success rate".to_string(), + "Failed to fetch the entity and global success rate".to_string(), ))? .into_inner(); @@ -254,10 +263,10 @@ impl ForeignTryFrom for CalSuccessRateConfig { .change_context(DynamicRoutingError::MissingRequiredField { field: "default_success_rate".to_string(), })?, - specificity_level: config.specificity_level.map(|level| match level { - SuccessRateSpecificityLevel::Merchant => ProtoSpecificityLevel::Entity.into(), - SuccessRateSpecificityLevel::Global => ProtoSpecificityLevel::Global.into(), - }), + specificity_level: match config.specificity_level { + SuccessRateSpecificityLevel::Merchant => Some(ProtoSpecificityLevel::Entity.into()), + SuccessRateSpecificityLevel::Global => Some(ProtoSpecificityLevel::Global.into()), + }, }) } } diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 2f068b5609b8..d306eff4e4a6 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -624,6 +624,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::routing::StraightThroughAlgorithm, api_models::routing::ConnectorVolumeSplit, api_models::routing::ConnectorSelection, + api_models::routing::SuccessRateSpecificityLevel, api_models::routing::ToggleDynamicRoutingQuery, api_models::routing::ToggleDynamicRoutingPath, api_models::routing::ast::RoutableChoiceKind, diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 2bd1bb40024c..0ff48f0b5790 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1340,11 +1340,6 @@ pub async fn perform_success_based_routing( .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) .attach_printable("unable to fetch success_rate based dynamic routing configs")?; - success_based_routing_configs.config.as_mut().map(|config| { - config.specificity_level = - Some(api_models::routing::SuccessRateSpecificityLevel::Merchant) - }); - let success_based_routing_config_params = success_based_routing_config_params_interpolator .get_string_val( success_based_routing_configs diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 4e280e6eb466..d8345e4ed181 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -709,8 +709,8 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( ); let success_based_connectors = client - .calculate_global_success_rate( - tenant_business_profile_id.clone(), + .calculate_entity_and_global_success_rate( + business_profile.get_id().get_string_repr().into(), success_based_routing_configs.clone(), success_based_routing_config_params.clone(), routable_connectors.clone(), @@ -743,23 +743,13 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( first_merchant_success_based_connector_label ))?; - let first_global_success_based_connector_label = &success_based_connectors + let first_global_success_based_connector = &success_based_connectors .global_scores_with_labels .first() .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable( - "unable to fetch the first connector from list of connectors obtained from dynamic routing service", - )? - .label - .to_string(); - - let (first_global_success_based_connector, _) = first_global_success_based_connector_label - .split_once(':') - .ok_or(errors::ApiErrorResponse::InternalServerError) - .attach_printable(format!( - "unable to split connector_name and mca_id from the first connector {:?} obtained from dynamic routing service", - first_global_success_based_connector_label - ))?; + "unable to fetch the first global connector from list of connectors obtained from dynamic routing service", + )?; let outcome = get_success_based_metrics_outcome_for_payment( payment_status_attribute, @@ -806,7 +796,11 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( ), ( "global_success_based_routing_connector", - first_global_success_based_connector.to_string(), + first_global_success_based_connector.label.to_string(), + ), + ( + "global_success_based_routing_connector_score", + first_global_success_based_connector.score.to_string(), ), ("payment_connector", payment_connector.to_string()), ( diff --git a/proto/success_rate.proto b/proto/success_rate.proto index bd990049b730..37e709712243 100644 --- a/proto/success_rate.proto +++ b/proto/success_rate.proto @@ -77,10 +77,13 @@ message InvalidateWindowsResponse { // API-4 types message CalGlobalSuccessRateRequest { - string id = 1; - string params = 2; - repeated string labels = 3; - CalGlobalSuccessRateConfig config = 4; + string entity_id = 1; + string entity_params = 2; + repeated string entity_labels = 3; + string global_id = 4; + string global_params = 5; + repeated string global_labels = 6; + CalGlobalSuccessRateConfig config = 7; } message CalGlobalSuccessRateConfig { From 138370b6bffdee8ae53eebdc0032bf5227f73a7d Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 11:50:12 +0000 Subject: [PATCH 08/17] docs(openapi): re-generate OpenAPI specification --- api-reference/openapi_spec.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index df7e96431dbc..c84442437c54 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -25162,9 +25162,19 @@ } ], "nullable": true + }, + "specificity_level": { + "$ref": "#/components/schemas/SuccessRateSpecificityLevel" } } }, + "SuccessRateSpecificityLevel": { + "type": "string", + "enum": [ + "merchant", + "global" + ] + }, "SupportedPaymentMethod": { "type": "object", "required": [ From c5a51ec8329dea61892da58c9c8a0c255ecf8267 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Fri, 3 Jan 2025 19:04:04 +0530 Subject: [PATCH 09/17] refactor: update proto file to include udpate sr request change --- .../dynamic_routing/success_rate_client.rs | 14 +++++++++++++- proto/success_rate.proto | 5 ++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index f3676802da6e..3973db75bc8f 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -118,6 +118,7 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { .transpose()?; let labels_with_status = label_input + .clone() .into_iter() .map(|conn_choice| LabelWithStatus { label: conn_choice.routable_connector_choice.to_string(), @@ -125,11 +126,22 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { }) .collect(); + let global_labels_with_status = label_input + .into_iter() + .map(|conn_choice| LabelWithStatus { + label: conn_choice.routable_connector_choice.connector.to_string(), + status: conn_choice.status, + }) + .collect(); + let mut request = tonic::Request::new(UpdateSuccessRateWindowRequest { id, - params, + params: params.clone(), labels_with_status, config, + global_id: "".to_string(), + global_params: params, + global_labels_with_status, }); request.add_headers_to_grpc_request(headers); diff --git a/proto/success_rate.proto b/proto/success_rate.proto index 37e709712243..94298e3611ad 100644 --- a/proto/success_rate.proto +++ b/proto/success_rate.proto @@ -44,7 +44,10 @@ message UpdateSuccessRateWindowRequest { string id = 1; string params = 2; repeated LabelWithStatus labels_with_status = 3; - UpdateSuccessRateWindowConfig config = 4; + string global_id = 4; + string global_params = 5; + repeated LabelWithStatus global_labels_with_status = 6; + UpdateSuccessRateWindowConfig config = 7; } message LabelWithStatus { From 4a3fe932a4f848cdaed6996a9226fb7c5d3e7c5b Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Mon, 6 Jan 2025 18:53:53 +0530 Subject: [PATCH 10/17] fix: Fixed proto file --- .../grpc_client/dynamic_routing/success_rate_client.rs | 2 -- proto/success_rate.proto | 10 ++++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index 3973db75bc8f..9bbbee364668 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -139,7 +139,6 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { params: params.clone(), labels_with_status, config, - global_id: "".to_string(), global_params: params, global_labels_with_status, }); @@ -205,7 +204,6 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { entity_id: id, entity_params: params.clone(), entity_labels: labels, - global_id: "".to_string(), global_params: params, global_labels, config, diff --git a/proto/success_rate.proto b/proto/success_rate.proto index 94298e3611ad..cc5d13032c7f 100644 --- a/proto/success_rate.proto +++ b/proto/success_rate.proto @@ -44,10 +44,9 @@ message UpdateSuccessRateWindowRequest { string id = 1; string params = 2; repeated LabelWithStatus labels_with_status = 3; - string global_id = 4; + UpdateSuccessRateWindowConfig config = 4; string global_params = 5; repeated LabelWithStatus global_labels_with_status = 6; - UpdateSuccessRateWindowConfig config = 7; } message LabelWithStatus { @@ -83,10 +82,9 @@ message CalGlobalSuccessRateRequest { string entity_id = 1; string entity_params = 2; repeated string entity_labels = 3; - string global_id = 4; - string global_params = 5; - repeated string global_labels = 6; - CalGlobalSuccessRateConfig config = 7; + string global_params = 4; + repeated string global_labels = 5; + CalGlobalSuccessRateConfig config = 6; } message CalGlobalSuccessRateConfig { From 3b5c637bdd12c14144eda3ed99c45f6ddbce6052 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Mon, 6 Jan 2025 19:21:49 +0530 Subject: [PATCH 11/17] fix: Fixed clippy errors --- crates/router/src/core/payments/routing.rs | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 0ff48f0b5790..8f3f40edf066 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1322,23 +1322,22 @@ pub async fn perform_success_based_routing( .ok_or(errors::RoutingError::SuccessRateClientInitializationError) .attach_printable("success_rate gRPC client not found")?; - let mut success_based_routing_configs = - routing::helpers::fetch_success_based_routing_configs( - state, - business_profile, - success_based_algo_ref - .algorithm_id_with_timestamp - .algorithm_id - .ok_or(errors::RoutingError::GenericNotFoundError { - field: "success_based_routing_algorithm_id".to_string(), - }) - .attach_printable( - "success_based_routing_algorithm_id not found in business_profile", - )?, - ) - .await - .change_context(errors::RoutingError::SuccessBasedRoutingConfigError) - .attach_printable("unable to fetch success_rate based dynamic routing configs")?; + let success_based_routing_configs = routing::helpers::fetch_success_based_routing_configs( + state, + business_profile, + success_based_algo_ref + .algorithm_id_with_timestamp + .algorithm_id + .ok_or(errors::RoutingError::GenericNotFoundError { + field: "success_based_routing_algorithm_id".to_string(), + }) + .attach_printable( + "success_based_routing_algorithm_id not found in business_profile", + )?, + ) + .await + .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( From 3c1c159b7b55f0e57cb012d83d32e58c80b7601e Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Tue, 7 Jan 2025 16:11:30 +0530 Subject: [PATCH 12/17] refactor: Added global connector to dynamic_routing_stats --- crates/diesel_models/src/dynamic_routing_stats.rs | 2 ++ crates/diesel_models/src/schema.rs | 2 ++ crates/router/src/core/routing/helpers.rs | 3 +++ .../down.sql | 3 +++ .../up.sql | 3 +++ 5 files changed, 13 insertions(+) create mode 100644 migrations/2025-01-07-101337_global_sr_connector_dynamic_routing/down.sql create mode 100644 migrations/2025-01-07-101337_global_sr_connector_dynamic_routing/up.sql diff --git a/crates/diesel_models/src/dynamic_routing_stats.rs b/crates/diesel_models/src/dynamic_routing_stats.rs index c055359d8b03..90cf46890806 100644 --- a/crates/diesel_models/src/dynamic_routing_stats.rs +++ b/crates/diesel_models/src/dynamic_routing_stats.rs @@ -20,6 +20,7 @@ pub struct DynamicRoutingStatsNew { pub conclusive_classification: common_enums::SuccessBasedRoutingConclusiveState, pub created_at: time::PrimitiveDateTime, pub payment_method_type: Option, + pub global_success_based_connector: Option, } #[derive(Clone, Debug, Eq, PartialEq, Queryable, Selectable, Insertable)] @@ -40,4 +41,5 @@ pub struct DynamicRoutingStats { pub conclusive_classification: common_enums::SuccessBasedRoutingConclusiveState, pub created_at: time::PrimitiveDateTime, pub payment_method_type: Option, + pub global_success_based_connector: Option, } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 37a39cb731a8..c12062560a20 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -419,6 +419,8 @@ diesel::table! { created_at -> Timestamp, #[max_length = 64] payment_method_type -> Nullable, + #[max_length = 64] + global_success_based_connector -> Nullable, } } diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index d8345e4ed181..9e7dfcf027e7 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -773,6 +773,9 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( payment_status: payment_attempt.status, conclusive_classification: outcome, created_at: common_utils::date_time::now(), + global_success_based_connector: Some( + first_global_success_based_connector.label.to_string(), + ), }; core_metrics::DYNAMIC_SUCCESS_BASED_ROUTING.add( diff --git a/migrations/2025-01-07-101337_global_sr_connector_dynamic_routing/down.sql b/migrations/2025-01-07-101337_global_sr_connector_dynamic_routing/down.sql new file mode 100644 index 000000000000..c99db9a384d1 --- /dev/null +++ b/migrations/2025-01-07-101337_global_sr_connector_dynamic_routing/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE dynamic_routing_stats +DROP COLUMN IF EXISTS global_success_based_connector; \ No newline at end of file diff --git a/migrations/2025-01-07-101337_global_sr_connector_dynamic_routing/up.sql b/migrations/2025-01-07-101337_global_sr_connector_dynamic_routing/up.sql new file mode 100644 index 000000000000..81e00a9753c4 --- /dev/null +++ b/migrations/2025-01-07-101337_global_sr_connector_dynamic_routing/up.sql @@ -0,0 +1,3 @@ +-- Your SQL goes here +ALTER TABLE dynamic_routing_stats +ADD COLUMN IF NOT EXISTS global_success_based_connector VARCHAR(64); \ No newline at end of file From 243763936b15432606dc8e821c1bc2734a566000 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Tue, 7 Jan 2025 17:39:05 +0530 Subject: [PATCH 13/17] fix: fixed proto file --- .../grpc_client/dynamic_routing/success_rate_client.rs | 4 +--- proto/success_rate.proto | 8 +++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index 9bbbee364668..511ac4d896b6 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -139,7 +139,6 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { params: params.clone(), labels_with_status, config, - global_params: params, global_labels_with_status, }); @@ -202,9 +201,8 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { let mut request = tonic::Request::new(CalGlobalSuccessRateRequest { entity_id: id, - entity_params: params.clone(), + entity_params: params, entity_labels: labels, - global_params: params, global_labels, config, }); diff --git a/proto/success_rate.proto b/proto/success_rate.proto index cc5d13032c7f..4b489e071c35 100644 --- a/proto/success_rate.proto +++ b/proto/success_rate.proto @@ -45,8 +45,7 @@ message UpdateSuccessRateWindowRequest { string params = 2; repeated LabelWithStatus labels_with_status = 3; UpdateSuccessRateWindowConfig config = 4; - string global_params = 5; - repeated LabelWithStatus global_labels_with_status = 6; + repeated LabelWithStatus global_labels_with_status = 5; } message LabelWithStatus { @@ -82,9 +81,8 @@ message CalGlobalSuccessRateRequest { string entity_id = 1; string entity_params = 2; repeated string entity_labels = 3; - string global_params = 4; - repeated string global_labels = 5; - CalGlobalSuccessRateConfig config = 6; + repeated string global_labels = 4; + CalGlobalSuccessRateConfig config = 5; } message CalGlobalSuccessRateConfig { From 8711e4396d4225d90274ad37f6fed4a0683e7b4e Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Tue, 7 Jan 2025 18:01:40 +0530 Subject: [PATCH 14/17] fix: Fixed schema_v2 --- crates/diesel_models/src/schema_v2.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 3e27f29427bb..a4669fa906bc 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -431,6 +431,8 @@ diesel::table! { created_at -> Timestamp, #[max_length = 64] payment_method_type -> Nullable, + #[max_length = 64] + global_success_based_connector -> Nullable, } } From dee929c270bba2d70abe994f9df698ac62bf4bac Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Wed, 15 Jan 2025 18:55:05 +0530 Subject: [PATCH 15/17] chore: Resolved comments --- crates/router/src/core/routing/helpers.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 9e7dfcf027e7..392b375c4b99 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -725,22 +725,20 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( let payment_status_attribute = get_desired_payment_status_for_success_routing_metrics(payment_attempt.status); - let first_merchant_success_based_connector_label = &success_based_connectors + let first_merchant_success_based_connector = &success_based_connectors .entity_scores_with_labels .first() .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable( "unable to fetch the first connector from list of connectors obtained from dynamic routing service", - )? - .label - .to_string(); + )?; - let (first_merchant_success_based_connector, _) = first_merchant_success_based_connector_label + let (first_merchant_success_based_connector_label, _) = first_merchant_success_based_connector.label .split_once(':') .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable(format!( "unable to split connector_name and mca_id from the first connector {:?} obtained from dynamic routing service", - first_merchant_success_based_connector_label + first_merchant_success_based_connector.label ))?; let first_global_success_based_connector = &success_based_connectors @@ -754,7 +752,7 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( let outcome = get_success_based_metrics_outcome_for_payment( payment_status_attribute, payment_connector.to_string(), - first_merchant_success_based_connector.to_string(), + first_merchant_success_based_connector_label.to_string(), ); let dynamic_routing_stats = DynamicRoutingStatsNew { @@ -763,7 +761,8 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( merchant_id: payment_attempt.merchant_id.to_owned(), profile_id: payment_attempt.profile_id.to_owned(), amount: payment_attempt.get_total_amount(), - success_based_routing_connector: first_merchant_success_based_connector.to_string(), + success_based_routing_connector: first_merchant_success_based_connector_label + .to_string(), payment_connector: payment_connector.to_string(), payment_method_type: payment_attempt.payment_method_type, currency: payment_attempt.currency, @@ -795,7 +794,11 @@ pub async fn push_metrics_with_update_window_for_success_based_routing( ), ( "merchant_specific_success_based_routing_connector", - first_merchant_success_based_connector.to_string(), + first_merchant_success_based_connector_label.to_string(), + ), + ( + "merchant_specific_success_based_routing_connector_score", + first_merchant_success_based_connector.score.to_string(), ), ( "global_success_based_routing_connector", From 164127c9e052ea9aa291409795e0705fc10b5c24 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 16 Jan 2025 20:15:18 +0530 Subject: [PATCH 16/17] fix: FIxed errors --- .../dynamic_routing/success_rate_client.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index a0e676742bed..7959fc370bc1 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -211,15 +211,16 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { .map(ForeignTryFrom::foreign_try_from) .transpose()?; - let mut request = tonic::Request::new(CalGlobalSuccessRateRequest { - entity_id: id, - entity_params: params, - entity_labels: labels, - global_labels, - config, - }); - - request.add_headers_to_grpc_request(headers); + let request = grpc_client::create_grpc_request( + CalGlobalSuccessRateRequest { + entity_id: id, + entity_params: params, + entity_labels: labels, + global_labels, + config, + }, + headers, + ); let response = self .clone() From 6b68a2950bef0983c2b581753f0771bf9d0e0127 Mon Sep 17 00:00:00 2001 From: Sarthak Soni Date: Thu, 16 Jan 2025 20:18:47 +0530 Subject: [PATCH 17/17] chore: Resolved comments --- .../src/grpc_client/dynamic_routing/success_rate_client.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs index 7959fc370bc1..278a2b50d157 100644 --- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs +++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs @@ -231,6 +231,8 @@ impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient { ))? .into_inner(); + logger::info!(dynamic_routing_response=?response); + Ok(response) } }