Bug: Elimination routing integration




diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs
index c4c2f072b1e..2e570816ab4 100644
--- a/crates/api_models/src/routing.rs
+++ b/crates/api_models/src/routing.rs
@@ -740,14 +740,13 @@ pub struct ToggleDynamicRoutingPath {
 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema)]
 pub struct EliminationRoutingConfig {
     pub params: Option<Vec<DynamicRoutingConfigParams>>,
-    // pub labels: Option<Vec<String>>,
     pub elimination_analyser_config: Option<EliminationAnalyserConfig>,
 }
 
 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema)]
 pub struct EliminationAnalyserConfig {
-    pub bucket_size: Option<u32>,
-    pub bucket_ttl_in_mins: Option<f64>,
+    pub bucket_size: Option<u64>,
+    pub bucket_leak_interval_in_secs: Option<u64>,
 }
 
 impl Default for EliminationRoutingConfig {
@@ -756,7 +755,7 @@ impl Default for EliminationRoutingConfig {
             params: Some(vec![DynamicRoutingConfigParams::PaymentMethod]),
             elimination_analyser_config: Some(EliminationAnalyserConfig {
                 bucket_size: Some(5),
-                bucket_ttl_in_mins: Some(2.0),
+                bucket_leak_interval_in_secs: Some(2),
             }),
         }
     }
@@ -860,3 +859,18 @@ impl CurrentBlockThreshold {
         }
     }
 }
+
+#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
+pub struct RoutableConnectorChoiceWithBucketName {
+    pub routable_connector_choice: RoutableConnectorChoice,
+    pub bucket_name: String,
+}
+
+impl RoutableConnectorChoiceWithBucketName {
+    pub fn new(routable_connector_choice: RoutableConnectorChoice, bucket_name: String) -> Self {
+        Self {
+            routable_connector_choice,
+            bucket_name,
+        }
+    }
+}
diff --git a/crates/external_services/build.rs b/crates/external_services/build.rs
index 0a4938e94b4..b3fa1a8fed2 100644
--- a/crates/external_services/build.rs
+++ b/crates/external_services/build.rs
@@ -6,7 +6,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
 
         let proto_path = router_env::workspace_path().join("proto");
         let success_rate_proto_file = proto_path.join("success_rate.proto");
-
+        let elimination_proto_file = proto_path.join("elimination_rate.proto");
         let health_check_proto_file = proto_path.join("health_check.proto");
         let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR")?);
 
@@ -14,7 +14,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
         tonic_build::configure()
             .out_dir(out_dir)
             .compile(
-                &[success_rate_proto_file, health_check_proto_file],
+                &[
+                    success_rate_proto_file,
+                    elimination_proto_file,
+                    health_check_proto_file,
+                ],
                 &[proto_path],
             )
             .expect("Failed to compile proto files");
diff --git a/crates/external_services/src/grpc_client/dynamic_routing.rs b/crates/external_services/src/grpc_client/dynamic_routing.rs
index 7ec42de0d7c..e5050227fa8 100644
--- a/crates/external_services/src/grpc_client/dynamic_routing.rs
+++ b/crates/external_services/src/grpc_client/dynamic_routing.rs
@@ -1,31 +1,17 @@
 use std::fmt::Debug;
 
-use api_models::routing::{
-    CurrentBlockThreshold, RoutableConnectorChoice, RoutableConnectorChoiceWithStatus,
-    SuccessBasedRoutingConfig, SuccessBasedRoutingConfigBody,
-};
-use common_utils::{errors::CustomResult, ext_traits::OptionExt, transformers::ForeignTryFrom};
-use error_stack::ResultExt;
+use common_utils::errors::CustomResult;
 use router_env::logger;
 use serde;
-use success_rate::{
-    success_rate_calculator_client::SuccessRateCalculatorClient, CalSuccessRateConfig,
-    CalSuccessRateRequest, CalSuccessRateResponse,
-    CurrentBlockThreshold as DynamicCurrentThreshold, InvalidateWindowsRequest,
-    InvalidateWindowsResponse, LabelWithStatus, UpdateSuccessRateWindowConfig,
-    UpdateSuccessRateWindowRequest, UpdateSuccessRateWindowResponse,
-};
+/// Elimination Routing Client Interface Implementation
+pub mod elimination_rate_client;
+/// Success Routing Client Interface Implementation
+pub mod success_rate_client;
+
+pub use elimination_rate_client::EliminationAnalyserClient;
+pub use success_rate_client::SuccessRateCalculatorClient;
 
 use super::Client;
-#[allow(
-    missing_docs,
-    unused_qualifications,
-    clippy::unwrap_used,
-    clippy::as_conversions
-)]
-pub mod success_rate {
-    tonic::include_proto!("success_rate");
-}
 /// Result type for Dynamic Routing
 pub type DynamicRoutingResult<T> = CustomResult<T, DynamicRoutingError>;
 
@@ -38,9 +24,12 @@ pub enum DynamicRoutingError {
         /// The required field name
         field: String,
     },
-    /// Error from Dynamic Routing Server
-    #[error("Error from Dynamic Routing Server : {0}")]
+    /// Error from Dynamic Routing Server while performing success_rate analysis
+    #[error("Error from Dynamic Routing Server while perfrming success_rate analysis : {0}")]
     SuccessRateBasedRoutingFailure(String),
+    /// Error from Dynamic Routing Server while perfrming elimination
+    #[error("Error from Dynamic Routing Server while perfrming elimination : {0}")]
+    EliminationRateRoutingFailure(String),
 }
 
 /// Type that consists of all the services provided by the client
@@ -48,6 +37,8 @@ pub enum DynamicRoutingError {
 pub struct RoutingStrategy {
     /// success rate service for Dynamic Routing
     pub success_rate_client: Option<SuccessRateCalculatorClient<Client>>,
+    /// elimination service for Dynamic Routing
+    pub elimination_rate_client: Option<EliminationAnalyserClient<Client>>,
 }
 
 /// Contains the Dynamic Routing Client Config
@@ -74,190 +65,23 @@ impl DynamicRoutingClientConfig {
         self,
         client: Client,
     ) -> Result<RoutingStrategy, Box<dyn std::error::Error>> {
-        let success_rate_client = match self {
+        let (success_rate_client, elimination_rate_client) = match self {
             Self::Enabled { host, port, .. } => {
                 let uri = format!("http://{}:{}", host, port).parse::<tonic::transport::Uri>()?;
                 logger::info!("Connection established with dynamic routing gRPC Server");
-                Some(SuccessRateCalculatorClient::with_origin(client, uri))
+                (
+                    Some(SuccessRateCalculatorClient::with_origin(
+                        client.clone(),
+                        uri.clone(),
+                    )),
+                    Some(EliminationAnalyserClient::with_origin(client, uri)),
+                )
             }
-            Self::Disabled => None,
+            Self::Disabled => (None, None),
         };
         Ok(RoutingStrategy {
             success_rate_client,
-        })
-    }
-}
-
-/// The trait Success Based Dynamic Routing would have the functions required to support the calculation and updation window
-#[async_trait::async_trait]
-pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync {
-    /// To calculate the success rate for the list of chosen connectors
-    async fn calculate_success_rate(
-        &self,
-        id: String,
-        success_rate_based_config: SuccessBasedRoutingConfig,
-        params: String,
-        label_input: Vec<RoutableConnectorChoice>,
-    ) -> DynamicRoutingResult<CalSuccessRateResponse>;
-    /// To update the success rate with the given label
-    async fn update_success_rate(
-        &self,
-        id: String,
-        success_rate_based_config: SuccessBasedRoutingConfig,
-        params: String,
-        response: Vec<RoutableConnectorChoiceWithStatus>,
-    ) -> DynamicRoutingResult<UpdateSuccessRateWindowResponse>;
-    /// To invalidates the success rate routing keys
-    async fn invalidate_success_rate_routing_keys(
-        &self,
-        id: String,
-    ) -> DynamicRoutingResult<InvalidateWindowsResponse>;
-}
-
-#[async_trait::async_trait]
-impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient<Client> {
-    async fn calculate_success_rate(
-        &self,
-        id: String,
-        success_rate_based_config: SuccessBasedRoutingConfig,
-        params: String,
-        label_input: Vec<RoutableConnectorChoice>,
-    ) -> DynamicRoutingResult<CalSuccessRateResponse> {
-        let labels = label_input
-            .into_iter()
-            .map(|conn_choice| conn_choice.to_string())
-            .collect::<Vec<_>>();
-
-        let config = success_rate_based_config
-            .config
-            .map(ForeignTryFrom::foreign_try_from)
-            .transpose()?;
-
-        let request = tonic::Request::new(CalSuccessRateRequest {
-            id,
-            params,
-            labels,
-            config,
-        });
-
-        let response = self
-            .clone()
-            .fetch_success_rate(request)
-            .await
-            .change_context(DynamicRoutingError::SuccessRateBasedRoutingFailure(
-                "Failed to fetch the success rate".to_string(),
-            ))?
-            .into_inner();
-
-        Ok(response)
-    }
-
-    async fn update_success_rate(
-        &self,
-        id: String,
-        success_rate_based_config: SuccessBasedRoutingConfig,
-        params: String,
-        label_input: Vec<RoutableConnectorChoiceWithStatus>,
-    ) -> DynamicRoutingResult<UpdateSuccessRateWindowResponse> {
-        let config = success_rate_based_config
-            .config
-            .map(ForeignTryFrom::foreign_try_from)
-            .transpose()?;
-
-        let labels_with_status = label_input
-            .into_iter()
-            .map(|conn_choice| LabelWithStatus {
-                label: conn_choice.routable_connector_choice.to_string(),
-                status: conn_choice.status,
-            })
-            .collect();
-
-        let request = tonic::Request::new(UpdateSuccessRateWindowRequest {
-            id,
-            params,
-            labels_with_status,
-            config,
-        });
-
-        let response = self
-            .clone()
-            .update_success_rate_window(request)
-            .await
-            .change_context(DynamicRoutingError::SuccessRateBasedRoutingFailure(
-                "Failed to update the success rate window".to_string(),
-            ))?
-            .into_inner();
-
-        Ok(response)
-    }
-
-    async fn invalidate_success_rate_routing_keys(
-        &self,
-        id: String,
-    ) -> DynamicRoutingResult<InvalidateWindowsResponse> {
-        let request = tonic::Request::new(InvalidateWindowsRequest { id });
-
-        let response = self
-            .clone()
-            .invalidate_windows(request)
-            .await
-            .change_context(DynamicRoutingError::SuccessRateBasedRoutingFailure(
-                "Failed to invalidate the success rate routing keys".to_string(),
-            ))?
-            .into_inner();
-        Ok(response)
-    }
-}
-
-impl ForeignTryFrom<CurrentBlockThreshold> for DynamicCurrentThreshold {
-    type Error = error_stack::Report<DynamicRoutingError>;
-    fn foreign_try_from(current_threshold: CurrentBlockThreshold) -> Result<Self, Self::Error> {
-        Ok(Self {
-            duration_in_mins: current_threshold.duration_in_mins,
-            max_total_count: current_threshold
-                .max_total_count
-                .get_required_value("max_total_count")
-                .change_context(DynamicRoutingError::MissingRequiredField {
-                    field: "max_total_count".to_string(),
-                })?,
-        })
-    }
-}
-
-impl ForeignTryFrom<SuccessBasedRoutingConfigBody> for UpdateSuccessRateWindowConfig {
-    type Error = error_stack::Report<DynamicRoutingError>;
-    fn foreign_try_from(config: SuccessBasedRoutingConfigBody) -> Result<Self, Self::Error> {
-        Ok(Self {
-            max_aggregates_size: config
-                .max_aggregates_size
-                .get_required_value("max_aggregate_size")
-                .change_context(DynamicRoutingError::MissingRequiredField {
-                    field: "max_aggregates_size".to_string(),
-                })?,
-            current_block_threshold: config
-                .current_block_threshold
-                .map(ForeignTryFrom::foreign_try_from)
-                .transpose()?,
-        })
-    }
-}
-
-impl ForeignTryFrom<SuccessBasedRoutingConfigBody> for CalSuccessRateConfig {
-    type Error = error_stack::Report<DynamicRoutingError>;
-    fn foreign_try_from(config: SuccessBasedRoutingConfigBody) -> Result<Self, Self::Error> {
-        Ok(Self {
-            min_aggregates_size: config
-                .min_aggregates_size
-                .get_required_value("min_aggregate_size")
-                .change_context(DynamicRoutingError::MissingRequiredField {
-                    field: "min_aggregates_size".to_string(),
-                })?,
-            default_success_rate: config
-                .default_success_rate
-                .get_required_value("default_success_rate")
-                .change_context(DynamicRoutingError::MissingRequiredField {
-                    field: "default_success_rate".to_string(),
-                })?,
+            elimination_rate_client,
         })
     }
 }
diff --git a/crates/external_services/src/grpc_client/dynamic_routing/elimination_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/elimination_rate_client.rs
new file mode 100644
index 00000000000..6587b7941f4
--- /dev/null
+++ b/crates/external_services/src/grpc_client/dynamic_routing/elimination_rate_client.rs
@@ -0,0 +1,158 @@
+use api_models::routing::{
+    EliminationAnalyserConfig as EliminationConfig, RoutableConnectorChoice,
+    RoutableConnectorChoiceWithBucketName,
+};
+use common_utils::{ext_traits::OptionExt, transformers::ForeignTryFrom};
+pub use elimination_rate::{
+    elimination_analyser_client::EliminationAnalyserClient, EliminationBucketConfig,
+    EliminationRequest, EliminationResponse, InvalidateBucketRequest, InvalidateBucketResponse,
+    LabelWithBucketName, UpdateEliminationBucketRequest, UpdateEliminationBucketResponse,
+};
+use error_stack::ResultExt;
+#[allow(
+    missing_docs,
+    unused_qualifications,
+    clippy::unwrap_used,
+    clippy::as_conversions,
+    clippy::use_self
+)]
+pub mod elimination_rate {
+    tonic::include_proto!("elimination");
+}
+
+use super::{Client, DynamicRoutingError, DynamicRoutingResult};
+
+/// The trait Elimination Based Routing would have the functions required to support performance, calculation and invalidation bucket
+#[async_trait::async_trait]
+pub trait EliminationBasedRouting: dyn_clone::DynClone + Send + Sync {
+    /// To perform the elimination based routing for the list of connectors
+    async fn perform_elimination_routing(
+        &self,
+        id: String,
+        params: String,
+        labels: Vec<RoutableConnectorChoice>,
+        configs: Option<EliminationConfig>,
+    ) -> DynamicRoutingResult<EliminationResponse>;
+    /// To update the bucket size and ttl for list of connectors with its respective bucket name
+    async fn update_elimination_bucket_config(
+        &self,
+        id: String,
+        params: String,
+        report: Vec<RoutableConnectorChoiceWithBucketName>,
+        config: Option<EliminationConfig>,
+    ) -> DynamicRoutingResult<UpdateEliminationBucketResponse>;
+    /// To invalidate the previous id's bucket
+    async fn invalidate_elimination_bucket(
+        &self,
+        id: String,
+    ) -> DynamicRoutingResult<InvalidateBucketResponse>;
+}
+
+#[async_trait::async_trait]
+impl EliminationBasedRouting for EliminationAnalyserClient<Client> {
+    async fn perform_elimination_routing(
+        &self,
+        id: String,
+        params: String,
+        label_input: Vec<RoutableConnectorChoice>,
+        configs: Option<EliminationConfig>,
+    ) -> DynamicRoutingResult<EliminationResponse> {
+        let labels = label_input
+            .into_iter()
+            .map(|conn_choice| conn_choice.to_string())
+            .collect::<Vec<_>>();
+
+        let config = configs.map(ForeignTryFrom::foreign_try_from).transpose()?;
+
+        let request = tonic::Request::new(EliminationRequest {
+            id,
+            params,
+            labels,
+            config,
+        });
+
+        let response = self
+            .clone()
+            .get_elimination_status(request)
+            .await
+            .change_context(DynamicRoutingError::EliminationRateRoutingFailure(
+                "Failed to perform the elimination analysis".to_string(),
+            ))?
+            .into_inner();
+
+        Ok(response)
+    }
+
+    async fn update_elimination_bucket_config(
+        &self,
+        id: String,
+        params: String,
+        report: Vec<RoutableConnectorChoiceWithBucketName>,
+        configs: Option<EliminationConfig>,
+    ) -> DynamicRoutingResult<UpdateEliminationBucketResponse> {
+        let config = configs.map(ForeignTryFrom::foreign_try_from).transpose()?;
+
+        let labels_with_bucket_name = report
+            .into_iter()
+            .map(|conn_choice_with_bucket| LabelWithBucketName {
+                label: conn_choice_with_bucket
+                    .routable_connector_choice
+                    .to_string(),
+                bucket_name: conn_choice_with_bucket.bucket_name,
+            })
+            .collect::<Vec<_>>();
+
+        let request = tonic::Request::new(UpdateEliminationBucketRequest {
+            id,
+            params,
+            labels_with_bucket_name,
+            config,
+        });
+
+        let response = self
+            .clone()
+            .update_elimination_bucket(request)
+            .await
+            .change_context(DynamicRoutingError::EliminationRateRoutingFailure(
+                "Failed to update the elimination bucket".to_string(),
+            ))?
+            .into_inner();
+        Ok(response)
+    }
+    async fn invalidate_elimination_bucket(
+        &self,
+        id: String,
+    ) -> DynamicRoutingResult<InvalidateBucketResponse> {
+        let request = tonic::Request::new(InvalidateBucketRequest { id });
+
+        let response = self
+            .clone()
+            .invalidate_bucket(request)
+            .await
+            .change_context(DynamicRoutingError::EliminationRateRoutingFailure(
+                "Failed to invalidate the elimination bucket".to_string(),
+            ))?
+            .into_inner();
+        Ok(response)
+    }
+}
+
+impl ForeignTryFrom<EliminationConfig> for EliminationBucketConfig {
+    type Error = error_stack::Report<DynamicRoutingError>;
+    fn foreign_try_from(config: EliminationConfig) -> Result<Self, Self::Error> {
+        Ok(Self {
+            bucket_size: config
+                .bucket_size
+                .get_required_value("bucket_size")
+                .change_context(DynamicRoutingError::MissingRequiredField {
+                    field: "bucket_size".to_string(),
+                })?,
+            bucket_leak_interval_in_secs: config
+                .bucket_leak_interval_in_secs
+                .get_required_value("bucket_leak_interval_in_secs")
+                .change_context(DynamicRoutingError::MissingRequiredField {
+                    field: "bucket_leak_interval_in_secs".to_string(),
+                })?,
+        })
+    }
+}
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
new file mode 100644
index 00000000000..f6d3efb8876
--- /dev/null
+++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs
@@ -0,0 +1,195 @@
+use api_models::routing::{
+    CurrentBlockThreshold, RoutableConnectorChoice, RoutableConnectorChoiceWithStatus,
+    SuccessBasedRoutingConfig, SuccessBasedRoutingConfigBody,
+};
+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,
+    UpdateSuccessRateWindowRequest, UpdateSuccessRateWindowResponse,
+};
+#[allow(
+    missing_docs,
+    unused_qualifications,
+    clippy::unwrap_used,
+    clippy::as_conversions
+)]
+pub mod success_rate {
+    tonic::include_proto!("success_rate");
+}
+use super::{Client, DynamicRoutingError, DynamicRoutingResult};
+/// The trait Success Based Dynamic Routing would have the functions required to support the calculation and updation window
+#[async_trait::async_trait]
+pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync {
+    /// To calculate the success rate for the list of chosen connectors
+    async fn calculate_success_rate(
+        &self,
+        id: String,
+        success_rate_based_config: SuccessBasedRoutingConfig,
+        params: String,
+        label_input: Vec<RoutableConnectorChoice>,
+    ) -> DynamicRoutingResult<CalSuccessRateResponse>;
+    /// To update the success rate with the given label
+    async fn update_success_rate(
+        &self,
+        id: String,
+        success_rate_based_config: SuccessBasedRoutingConfig,
+        params: String,
+        response: Vec<RoutableConnectorChoiceWithStatus>,
+    ) -> DynamicRoutingResult<UpdateSuccessRateWindowResponse>;
+    /// To invalidates the success rate routing keys
+    async fn invalidate_success_rate_routing_keys(
+        &self,
+        id: String,
+    ) -> DynamicRoutingResult<InvalidateWindowsResponse>;
+}
+
+#[async_trait::async_trait]
+impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient<Client> {
+    async fn calculate_success_rate(
+        &self,
+        id: String,
+        success_rate_based_config: SuccessBasedRoutingConfig,
+        params: String,
+        label_input: Vec<RoutableConnectorChoice>,
+    ) -> DynamicRoutingResult<CalSuccessRateResponse> {
+        let labels = label_input
+            .into_iter()
+            .map(|conn_choice| conn_choice.to_string())
+            .collect::<Vec<_>>();
+
+        let config = success_rate_based_config
+            .config
+            .map(ForeignTryFrom::foreign_try_from)
+            .transpose()?;
+
+        let request = tonic::Request::new(CalSuccessRateRequest {
+            id,
+            params,
+            labels,
+            config,
+        });
+
+        let response = self
+            .clone()
+            .fetch_success_rate(request)
+            .await
+            .change_context(DynamicRoutingError::SuccessRateBasedRoutingFailure(
+                "Failed to fetch the success rate".to_string(),
+            ))?
+            .into_inner();
+
+        Ok(response)
+    }
+
+    async fn update_success_rate(
+        &self,
+        id: String,
+        success_rate_based_config: SuccessBasedRoutingConfig,
+        params: String,
+        label_input: Vec<RoutableConnectorChoiceWithStatus>,
+    ) -> DynamicRoutingResult<UpdateSuccessRateWindowResponse> {
+        let config = success_rate_based_config
+            .config
+            .map(ForeignTryFrom::foreign_try_from)
+            .transpose()?;
+
+        let labels_with_status = label_input
+            .into_iter()
+            .map(|conn_choice| LabelWithStatus {
+                label: conn_choice.routable_connector_choice.to_string(),
+                status: conn_choice.status,
+            })
+            .collect();
+
+        let request = tonic::Request::new(UpdateSuccessRateWindowRequest {
+            id,
+            params,
+            labels_with_status,
+            config,
+        });
+
+        let response = self
+            .clone()
+            .update_success_rate_window(request)
+            .await
+            .change_context(DynamicRoutingError::SuccessRateBasedRoutingFailure(
+                "Failed to update the success rate window".to_string(),
+            ))?
+            .into_inner();
+
+        Ok(response)
+    }
+    async fn invalidate_success_rate_routing_keys(
+        &self,
+        id: String,
+    ) -> DynamicRoutingResult<InvalidateWindowsResponse> {
+        let request = tonic::Request::new(InvalidateWindowsRequest { id });
+
+        let response = self
+            .clone()
+            .invalidate_windows(request)
+            .await
+            .change_context(DynamicRoutingError::SuccessRateBasedRoutingFailure(
+                "Failed to invalidate the success rate routing keys".to_string(),
+            ))?
+            .into_inner();
+        Ok(response)
+    }
+}
+
+impl ForeignTryFrom<CurrentBlockThreshold> for DynamicCurrentThreshold {
+    type Error = error_stack::Report<DynamicRoutingError>;
+    fn foreign_try_from(current_threshold: CurrentBlockThreshold) -> Result<Self, Self::Error> {
+        Ok(Self {
+            duration_in_mins: current_threshold.duration_in_mins,
+            max_total_count: current_threshold
+                .max_total_count
+                .get_required_value("max_total_count")
+                .change_context(DynamicRoutingError::MissingRequiredField {
+                    field: "max_total_count".to_string(),
+                })?,
+        })
+    }
+}
+
+impl ForeignTryFrom<SuccessBasedRoutingConfigBody> for UpdateSuccessRateWindowConfig {
+    type Error = error_stack::Report<DynamicRoutingError>;
+    fn foreign_try_from(config: SuccessBasedRoutingConfigBody) -> Result<Self, Self::Error> {
+        Ok(Self {
+            max_aggregates_size: config
+                .max_aggregates_size
+                .get_required_value("max_aggregate_size")
+                .change_context(DynamicRoutingError::MissingRequiredField {
+                    field: "max_aggregates_size".to_string(),
+                })?,
+            current_block_threshold: config
+                .current_block_threshold
+                .map(ForeignTryFrom::foreign_try_from)
+                .transpose()?,
+        })
+    }
+}
+
+impl ForeignTryFrom<SuccessBasedRoutingConfigBody> for CalSuccessRateConfig {
+    type Error = error_stack::Report<DynamicRoutingError>;
+    fn foreign_try_from(config: SuccessBasedRoutingConfigBody) -> Result<Self, Self::Error> {
+        Ok(Self {
+            min_aggregates_size: config
+                .min_aggregates_size
+                .get_required_value("min_aggregate_size")
+                .change_context(DynamicRoutingError::MissingRequiredField {
+                    field: "min_aggregates_size".to_string(),
+                })?,
+            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 b3be47a8743..746b6b7fb40 100644
--- a/crates/router/src/core/payments/routing.rs
+++ b/crates/router/src/core/payments/routing.rs
@@ -23,8 +23,8 @@ use euclid::{
     frontend::{ast, dir as euclid_dir},
 };
 #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
-use external_services::grpc_client::dynamic_routing::{
-    success_rate::CalSuccessRateResponse, SuccessBasedDynamicRouting,
+use external_services::grpc_client::dynamic_routing::success_rate_client::{
+    CalSuccessRateResponse, SuccessBasedDynamicRouting,
 };
 use hyperswitch_domain_models::address::Address;
 use kgraph_utils::{
diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs
index cdd8b518f35..22301d4314f 100644
--- a/crates/router/src/core/routing.rs
+++ b/crates/router/src/core/routing.rs
@@ -12,7 +12,7 @@ use common_utils::ext_traits::AsyncExt;
 use diesel_models::routing_algorithm::RoutingAlgorithm;
 use error_stack::ResultExt;
 #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
-use external_services::grpc_client::dynamic_routing::SuccessBasedDynamicRouting;
+use external_services::grpc_client::dynamic_routing::success_rate_client::SuccessBasedDynamicRouting;
 use hyperswitch_domain_models::{mandates, payment_address};
 #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
 use router_env::logger;
diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs
index 6a5e3bd0264..89fc29cf1b2 100644
--- a/crates/router/src/core/routing/helpers.rs
+++ b/crates/router/src/core/routing/helpers.rs
@@ -16,7 +16,7 @@ use diesel_models::configs;
 use diesel_models::routing_algorithm;
 use error_stack::ResultExt;
 #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
-use external_services::grpc_client::dynamic_routing::SuccessBasedDynamicRouting;
+use external_services::grpc_client::dynamic_routing::success_rate_client::SuccessBasedDynamicRouting;
 #[cfg(feature = "v1")]
 use hyperswitch_domain_models::api::ApplicationResponse;
 #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
diff --git a/proto/elimination_rate.proto b/proto/elimination_rate.proto
new file mode 100644
index 00000000000..c5f10597ade
--- /dev/null
+++ b/proto/elimination_rate.proto
@@ -0,0 +1,67 @@
+syntax = "proto3";
+package elimination;
+
+service EliminationAnalyser {
+    rpc GetEliminationStatus (EliminationRequest) returns (EliminationResponse);
+
+    rpc UpdateEliminationBucket (UpdateEliminationBucketRequest) returns (UpdateEliminationBucketResponse);
+
+    rpc InvalidateBucket (InvalidateBucketRequest) returns (InvalidateBucketResponse);
+}
+
+// API-1 types
+message EliminationRequest {
+    string id = 1;
+    string params = 2;
+    repeated string labels = 3;
+    EliminationBucketConfig config = 4;
+}
+
+message EliminationBucketConfig {
+    uint64 bucket_size = 1;
+    uint64 bucket_leak_interval_in_secs = 2;
+}
+
+message EliminationResponse {
+    repeated LabelWithStatus labels_with_status = 1;
+}
+
+message LabelWithStatus {
+    string label = 1;
+    bool is_eliminated = 2; 
+    string bucket_name = 3;
+}
+
+// API-2 types
+message UpdateEliminationBucketRequest {
+    string id = 1;
+    string params = 2;
+    repeated LabelWithBucketName labels_with_bucket_name = 3;
+    EliminationBucketConfig config = 4;
+}
+
+message LabelWithBucketName {
+    string label = 1;
+    string bucket_name = 2;
+}
+
+message UpdateEliminationBucketResponse {
+   enum UpdationStatus {
+      BUCKET_UPDATION_SUCCEEDED = 0;
+      BUCKET_UPDATION_FAILED = 1;
+   }
+   UpdationStatus status = 1;
+}
+
+// API-3 types
+message InvalidateBucketRequest {
+    string id = 1;
+}
+
+message InvalidateBucketResponse {
+    enum InvalidationStatus {
+        BUCKET_INVALIDATION_SUCCEEDED = 0;
+        BUCKET_INVALIDATION_FAILED = 1;
+    }
+    InvalidationStatus status = 1;
+}
\ No newline at end of file


## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
build the gRPC interface for communicating with the external service to perform elimination routing


### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
- Communication is being established with dynamo
<img width="1705" alt="Screenshot 2024-12-05 at 6 03 54 PM" src="https://github.com/user-attachments/assets/09c62052-6c86-47a2-b03f-da0c2835df55">



## Checklist
<!-- Put an `x` in the boxes that apply -->

- [ ] I formatted the code `cargo +nightly fmt --all`
- [ ] I addressed lints thrown by `cargo clippy`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
