Bug: [BUG] Make get_redis_conn return result in StorageInterface



### Bug Description

Currently `get_redis_conn` function in StorageInterface exposes `redis_conn` directly instead use `redis_conn()` function from `Store` and return Result in this function.

### Expected Behavior

It should return err in case of redis connection goes down

### Actual Behavior

It waits forever to connect to redis

### Steps To Reproduce

1. Run the application
2. Stop redis service
3. Try to do some redis operation

### Context For The Bug

_No response_

### Environment

Are you using hyperswitch hosted version? No
Rust Version: 1.70.0

### Have you spent some time to check if this bug has been raised before?

- [X] I checked and didn't find similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

None
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 67f498c1e99..00a647ed5c9 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -1713,7 +1713,12 @@ pub async fn list_customer_payment_method(
         };
         customer_pms.push(pma.to_owned());
 
-        let redis_conn = state.store.get_redis_conn();
+        let redis_conn = state
+            .store
+            .get_redis_conn()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to get redis connection")?;
+
         let key_for_hyperswitch_token = format!(
             "pm_token_{}_{}_hyperswitch",
             parent_payment_method_token, pma.payment_method
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index bb98368a7e8..b0a4fb3fb71 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -920,7 +920,12 @@ async fn decide_payment_method_tokenize_action(
             }
         }
         Some(token) => {
-            let redis_conn = state.store.get_redis_conn();
+            let redis_conn = state
+                .store
+                .get_redis_conn()
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed to get redis connection")?;
+
             let key = format!(
                 "pm_token_{}_{}_{}",
                 token.to_owned(),
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index a38c3677fd3..60e889ee629 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -1175,7 +1175,12 @@ pub async fn make_pm_data<'a, F: Clone, R>(
     let request = &payment_data.payment_method_data;
     let token = payment_data.token.clone();
     let hyperswitch_token = if let Some(token) = token {
-        let redis_conn = state.store.get_redis_conn();
+        let redis_conn = state
+            .store
+            .get_redis_conn()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to get redis connection")?;
+
         let key = format!(
             "pm_token_{}_{}_hyperswitch",
             token,
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index da2934c4c5d..462e569bb36 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -46,7 +46,12 @@ pub async fn make_payout_method_data<'a>(
             )
         );
 
-        let redis_conn = state.store.get_redis_conn();
+        let redis_conn = state
+            .store
+            .get_redis_conn()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to get redis connection")?;
+
         let hyperswitch_token_option = redis_conn
             .get_key::<Option<String>>(&key)
             .await
diff --git a/crates/router/src/db.rs b/crates/router/src/db.rs
index 6880bbe8c5b..00669d9ce78 100644
--- a/crates/router/src/db.rs
+++ b/crates/router/src/db.rs
@@ -173,8 +173,13 @@ where
 }
 
 impl services::RedisConnInterface for MockDb {
-    fn get_redis_conn(&self) -> Arc<redis_interface::RedisConnectionPool> {
-        self.redis.clone()
+    fn get_redis_conn(
+        &self,
+    ) -> Result<
+        Arc<redis_interface::RedisConnectionPool>,
+        error_stack::Report<redis_interface::errors::RedisError>,
+    > {
+        Ok(self.redis.clone())
     }
 }
 
diff --git a/crates/router/src/db/api_keys.rs b/crates/router/src/db/api_keys.rs
index 512664f517b..ad767a69277 100644
--- a/crates/router/src/db/api_keys.rs
+++ b/crates/router/src/db/api_keys.rs
@@ -470,7 +470,7 @@ mod tests {
     async fn test_api_keys_cache() {
         let db = MockDb::new(&Default::default()).await;
 
-        let redis_conn = db.get_redis_conn();
+        let redis_conn = db.get_redis_conn().unwrap();
         redis_conn
             .subscribe("hyperswitch_invalidate")
             .await
diff --git a/crates/router/src/db/cache.rs b/crates/router/src/db/cache.rs
index e22ab31cfab..fee7cd85912 100644
--- a/crates/router/src/db/cache.rs
+++ b/crates/router/src/db/cache.rs
@@ -1,5 +1,6 @@
 use common_utils::ext_traits::AsyncExt;
 use error_stack::ResultExt;
+use redis_interface::errors::RedisError;
 
 use super::StorageInterface;
 use crate::{
@@ -20,7 +21,12 @@ where
     Fut: futures::Future<Output = CustomResult<T, errors::StorageError>> + Send,
 {
     let type_name = std::any::type_name::<T>();
-    let redis = &store.get_redis_conn();
+    let redis = &store
+        .get_redis_conn()
+        .change_context(errors::StorageError::RedisError(
+            RedisError::RedisConnectionError.into(),
+        ))
+        .attach_printable("Failed to get redis connection")?;
     let redis_val = redis.get_and_deserialize_key::<T>(key, type_name).await;
     let get_data_set_redis = || async {
         let data = fun().await?;
@@ -76,8 +82,15 @@ where
 {
     let data = fun().await?;
     in_memory.async_map(|cache| cache.invalidate(key)).await;
-    store
+
+    let redis_conn = store
         .get_redis_conn()
+        .change_context(errors::StorageError::RedisError(
+            RedisError::RedisConnectionError.into(),
+        ))
+        .attach_printable("Failed to get redis connection")?;
+
+    redis_conn
         .delete_key(key)
         .await
         .change_context(errors::StorageError::KVError)?;
@@ -88,8 +101,14 @@ pub async fn publish_into_redact_channel<'a>(
     store: &dyn StorageInterface,
     key: cache::CacheKind<'a>,
 ) -> CustomResult<usize, errors::StorageError> {
-    store
+    let redis_conn = store
         .get_redis_conn()
+        .change_context(errors::StorageError::RedisError(
+            RedisError::RedisConnectionError.into(),
+        ))
+        .attach_printable("Failed to get redis connection")?;
+
+    redis_conn
         .publish(consts::PUB_SUB_CHANNEL, key)
         .await
         .change_context(errors::StorageError::KVError)
diff --git a/crates/router/src/db/merchant_connector_account.rs b/crates/router/src/db/merchant_connector_account.rs
index 6c47fb7f5d6..5808d3f3dbf 100644
--- a/crates/router/src/db/merchant_connector_account.rs
+++ b/crates/router/src/db/merchant_connector_account.rs
@@ -689,7 +689,7 @@ mod merchant_connector_account_cache_tests {
     async fn test_connector_label_cache() {
         let db = MockDb::new(&Default::default()).await;
 
-        let redis_conn = db.get_redis_conn();
+        let redis_conn = db.get_redis_conn().unwrap();
         let master_key = db.get_master_key();
         redis_conn
             .subscribe("hyperswitch_invalidate")
diff --git a/crates/router/src/routes/dummy_connector/core.rs b/crates/router/src/routes/dummy_connector/core.rs
index 50b91fab0c7..b32d3d8684d 100644
--- a/crates/router/src/routes/dummy_connector/core.rs
+++ b/crates/router/src/routes/dummy_connector/core.rs
@@ -91,7 +91,12 @@ pub async fn payment_complete(
         types::DummyConnectorStatus::Failed
     };
 
-    let redis_conn = state.store.get_redis_conn();
+    let redis_conn = state
+        .store
+        .get_redis_conn()
+        .change_context(errors::DummyConnectorErrors::InternalServerError)
+        .attach_printable("Failed to get redis connection")?;
+
     let _ = redis_conn.delete_key(req.attempt_id.as_str()).await;
 
     if let Ok(payment_data) = payment_data {
@@ -193,7 +198,11 @@ pub async fn refund_data(
     )
     .await;
 
-    let redis_conn = state.store.get_redis_conn();
+    let redis_conn = state
+        .store
+        .get_redis_conn()
+        .change_context(errors::DummyConnectorErrors::InternalServerError)
+        .attach_printable("Failed to get redis connection")?;
     let refund_data = redis_conn
         .get_and_deserialize_key::<types::DummyConnectorRefundResponse>(
             refund_id.as_str(),
diff --git a/crates/router/src/routes/dummy_connector/utils.rs b/crates/router/src/routes/dummy_connector/utils.rs
index 1f56f365372..937f0d0e1a4 100644
--- a/crates/router/src/routes/dummy_connector/utils.rs
+++ b/crates/router/src/routes/dummy_connector/utils.rs
@@ -25,7 +25,11 @@ pub async fn store_data_in_redis(
     data: impl serde::Serialize + Debug,
     ttl: i64,
 ) -> types::DummyConnectorResult<()> {
-    let redis_conn = state.store.get_redis_conn();
+    let redis_conn = state
+        .store
+        .get_redis_conn()
+        .change_context(errors::DummyConnectorErrors::InternalServerError)
+        .attach_printable("Failed to get redis connection")?;
 
     redis_conn
         .serialize_and_set_key_with_expiry(&key, data, ttl)
@@ -39,7 +43,12 @@ pub async fn get_payment_data_from_payment_id(
     state: &AppState,
     payment_id: String,
 ) -> types::DummyConnectorResult<types::DummyConnectorPaymentData> {
-    let redis_conn = state.store.get_redis_conn();
+    let redis_conn = state
+        .store
+        .get_redis_conn()
+        .change_context(errors::DummyConnectorErrors::InternalServerError)
+        .attach_printable("Failed to get redis connection")?;
+
     redis_conn
         .get_and_deserialize_key::<types::DummyConnectorPaymentData>(
             payment_id.as_str(),
@@ -53,7 +62,12 @@ pub async fn get_payment_data_by_attempt_id(
     state: &AppState,
     attempt_id: String,
 ) -> types::DummyConnectorResult<types::DummyConnectorPaymentData> {
-    let redis_conn = state.store.get_redis_conn();
+    let redis_conn = state
+        .store
+        .get_redis_conn()
+        .change_context(errors::DummyConnectorErrors::InternalServerError)
+        .attach_printable("Failed to get redis connection")?;
+
     redis_conn
         .get_and_deserialize_key::<String>(attempt_id.as_str(), "String")
         .await
diff --git a/crates/router/src/services.rs b/crates/router/src/services.rs
index afb37f99d3a..e82b2c7c42f 100644
--- a/crates/router/src/services.rs
+++ b/crates/router/src/services.rs
@@ -106,12 +106,22 @@ impl PubSubInterface for redis_interface::RedisConnectionPool {
 }
 
 pub trait RedisConnInterface {
-    fn get_redis_conn(&self) -> Arc<redis_interface::RedisConnectionPool>;
+    fn get_redis_conn(
+        &self,
+    ) -> common_utils::errors::CustomResult<
+        Arc<redis_interface::RedisConnectionPool>,
+        errors::RedisError,
+    >;
 }
 
 impl RedisConnInterface for Store {
-    fn get_redis_conn(&self) -> Arc<redis_interface::RedisConnectionPool> {
-        self.redis_conn.clone()
+    fn get_redis_conn(
+        &self,
+    ) -> common_utils::errors::CustomResult<
+        Arc<redis_interface::RedisConnectionPool>,
+        errors::RedisError,
+    > {
+        self.redis_conn()
     }
 }
 
diff --git a/crates/router/tests/cache.rs b/crates/router/tests/cache.rs
index e918d0f4c7b..0799335ee15 100644
--- a/crates/router/tests/cache.rs
+++ b/crates/router/tests/cache.rs
@@ -19,6 +19,7 @@ async fn invalidate_existing_cache_success() {
     let _ = state
         .store
         .get_redis_conn()
+        .unwrap()
         .set_key(&cache_key.clone(), cache_key_value.clone())
         .await;
 
diff --git a/crates/router/tests/services.rs b/crates/router/tests/services.rs
new file mode 100644
index 00000000000..34dbcac4c9d
--- /dev/null
+++ b/crates/router/tests/services.rs
@@ -0,0 +1,39 @@
+use std::sync::atomic;
+
+use router::{configs::settings::Settings, routes};
+
+mod utils;
+
+#[tokio::test]
+#[should_panic]
+async fn get_redis_conn_failure() {
+    // Arrange
+    utils::setup().await;
+    let (tx, _) = tokio::sync::oneshot::channel();
+    let state = routes::AppState::new(Settings::default(), tx).await;
+
+    let _ = state.store.get_redis_conn().map(|conn| {
+        conn.is_redis_available
+            .store(false, atomic::Ordering::SeqCst)
+    });
+
+    // Act
+    let _ = state.store.get_redis_conn();
+
+    // Assert
+    // based on #[should_panic] attribute
+}
+
+#[tokio::test]
+async fn get_redis_conn_success() {
+    // Arrange
+    utils::setup().await;
+    let (tx, _) = tokio::sync::oneshot::channel();
+    let state = routes::AppState::new(Settings::default(), tx).await;
+
+    // Act
+    let result = state.store.get_redis_conn();
+
+    // Assert
+    assert!(result.is_ok())
+}

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

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

## Description
Fixes #1497 

## Motivation and Context
Please find the details in the issue [1497](https://github.com/juspay/hyperswitch/issues/1497)


## How did you test it?
unit tests and postman

## 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 submitted code
- [X] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
