Bug: fix: lazy connection pools for dynamic routing service




diff --git a/Cargo.lock b/Cargo.lock
index 9ccedba3c39..78ae2d63adb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3126,8 +3126,10 @@ dependencies = [
  "dyn-clone",
  "error-stack",
  "hex",
+ "http-body-util",
  "hyper 0.14.30",
  "hyper-proxy",
+ "hyper-util",
  "hyperswitch_interfaces",
  "masking",
  "once_cell",
@@ -3959,9 +3961,9 @@ dependencies = [
 
 [[package]]
 name = "hyper-util"
-version = "0.1.7"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9"
+checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
 dependencies = [
  "bytes 1.7.1",
  "futures-channel",
@@ -3972,7 +3974,6 @@ dependencies = [
  "pin-project-lite",
  "socket2",
  "tokio 1.40.0",
- "tower",
  "tower-service",
  "tracing",
 ]
diff --git a/crates/external_services/Cargo.toml b/crates/external_services/Cargo.toml
index 735ccc5ebfa..12b9dd3b0f3 100644
--- a/crates/external_services/Cargo.toml
+++ b/crates/external_services/Cargo.toml
@@ -13,7 +13,7 @@ email = ["dep:aws-config"]
 aws_s3 = ["dep:aws-config", "dep:aws-sdk-s3"]
 hashicorp-vault = ["dep:vaultrs"]
 v1 = ["hyperswitch_interfaces/v1", "common_utils/v1"]
-dynamic_routing = ["dep:prost", "dep:tonic", "dep:tonic-reflection", "dep:tonic-types", "dep:api_models", "tokio/macros", "tokio/rt-multi-thread", "dep:tonic-build", "dep:router_env"]
+dynamic_routing = ["dep:prost", "dep:tonic", "dep:tonic-reflection", "dep:tonic-types", "dep:api_models", "tokio/macros", "tokio/rt-multi-thread", "dep:tonic-build", "dep:router_env", "dep:hyper-util", "dep:http-body-util"]
 
 [dependencies]
 async-trait = "0.1.79"
@@ -38,6 +38,8 @@ tokio = "1.37.0"
 tonic = { version = "0.12.2", optional = true }
 tonic-reflection = { version = "0.12.2", optional = true }
 tonic-types = { version = "0.12.2", optional = true }
+hyper-util = { version = "0.1.9", optional = true }
+http-body-util = { version = "0.1.2", optional = true }
 
 
 # First party crates
diff --git a/crates/external_services/src/grpc_client/dynamic_routing.rs b/crates/external_services/src/grpc_client/dynamic_routing.rs
index 2681bffb0ce..343dd80e951 100644
--- a/crates/external_services/src/grpc_client/dynamic_routing.rs
+++ b/crates/external_services/src/grpc_client/dynamic_routing.rs
@@ -6,6 +6,9 @@ use api_models::routing::{
 };
 use common_utils::{errors::CustomResult, ext_traits::OptionExt, transformers::ForeignTryFrom};
 use error_stack::ResultExt;
+use http_body_util::combinators::UnsyncBoxBody;
+use hyper::body::Bytes;
+use hyper_util::client::legacy::connect::HttpConnector;
 use serde;
 use success_rate::{
     success_rate_calculator_client::SuccessRateCalculatorClient, CalSuccessRateConfig,
@@ -13,7 +16,7 @@ use success_rate::{
     CurrentBlockThreshold as DynamicCurrentThreshold, LabelWithStatus,
     UpdateSuccessRateWindowConfig, UpdateSuccessRateWindowRequest, UpdateSuccessRateWindowResponse,
 };
-use tonic::transport::Channel;
+use tonic::Status;
 #[allow(
     missing_docs,
     unused_qualifications,
@@ -40,11 +43,13 @@ pub enum DynamicRoutingError {
     SuccessRateBasedRoutingFailure(String),
 }
 
+type Client = hyper_util::client::legacy::Client<HttpConnector, UnsyncBoxBody<Bytes, Status>>;
+
 /// Type that consists of all the services provided by the client
 #[derive(Debug, Clone)]
 pub struct RoutingStrategy {
     /// success rate service for Dynamic Routing
-    pub success_rate_client: Option<SuccessRateCalculatorClient<Channel>>,
+    pub success_rate_client: Option<SuccessRateCalculatorClient<Client>>,
 }
 
 /// Contains the Dynamic Routing Client Config
@@ -68,11 +73,14 @@ impl DynamicRoutingClientConfig {
     pub async fn get_dynamic_routing_connection(
         self,
     ) -> Result<RoutingStrategy, Box<dyn std::error::Error>> {
+        let client =
+            hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new())
+                .http2_only(true)
+                .build_http();
         let success_rate_client = match self {
             Self::Enabled { host, port } => {
-                let uri = format!("http://{}:{}", host, port);
-                let channel = tonic::transport::Endpoint::new(uri)?.connect().await?;
-                Some(SuccessRateCalculatorClient::new(channel))
+                let uri = format!("http://{}:{}", host, port).parse::<tonic::transport::Uri>()?;
+                Some(SuccessRateCalculatorClient::with_origin(client, uri))
             }
             Self::Disabled => None,
         };
@@ -102,7 +110,7 @@ pub trait SuccessBasedDynamicRouting: dyn_clone::DynClone + Send + Sync {
 }
 
 #[async_trait::async_trait]
-impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient<Channel> {
+impl SuccessBasedDynamicRouting for SuccessRateCalculatorClient<Client> {
     async fn calculate_success_rate(
         &self,
         id: String,

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

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

## Description
<!-- Describe your changes in detail -->
Previously hyperswitch server was panicking, if it wasn't able to establish a connection with dynamic_routing service. We have fixed this by establishing lazy connection pools and not established channel(which was previously). Which will insure hyperswitch server to run even when the connection isn't established.

### 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?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Tested on my local.
<img width="1728" alt="Screenshot 2024-10-25 at 4 15 03 PM" src="https://github.com/user-attachments/assets/a7a1d6c8-8c6c-4b35-ae3a-b05b6af9f9bc">
This can't be tested on Integ as we don't have this service on integ.
Can't be tested on sbx as well, as it will require the pods to be killed. and a re-establishment of connection.

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

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