diff --git a/crates/api_models/src/health_check.rs b/crates/api_models/src/health_check.rs index 4a1c009e43e..a6261da1be0 100644 --- a/crates/api_models/src/health_check.rs +++ b/crates/api_models/src/health_check.rs @@ -12,6 +12,8 @@ pub struct RouterHealthCheckResponse { pub outgoing_request: bool, #[cfg(feature = "dynamic_routing")] pub grpc_health_check: HealthCheckMap, + #[cfg(feature = "dynamic_routing")] + pub decision_engine: bool, } impl common_utils::events::ApiEventMetric for RouterHealthCheckResponse {} diff --git a/crates/router/src/core/health_check.rs b/crates/router/src/core/health_check.rs index c4892c94d6f..49138d3bda0 100644 --- a/crates/router/src/core/health_check.rs +++ b/crates/router/src/core/health_check.rs @@ -35,6 +35,11 @@ pub trait HealthCheckInterface { async fn health_check_grpc( &self, ) -> CustomResult; + + #[cfg(feature = "dynamic_routing")] + async fn health_check_decision_engine( + &self, + ) -> CustomResult; } #[async_trait::async_trait] @@ -184,4 +189,25 @@ impl HealthCheckInterface for app::SessionState { logger::debug!("Health check successful"); Ok(health_check_map) } + + #[cfg(feature = "dynamic_routing")] + async fn health_check_decision_engine( + &self, + ) -> CustomResult { + if self.conf.open_router.enabled { + let url = format!("{}/{}", &self.conf.open_router.url, "health"); + let request = services::Request::new(services::Method::Get, &url); + let _ = services::call_connector_api(self, request, "health_check_for_decision_engine") + .await + .change_context( + errors::HealthCheckDecisionEngineError::FailedToCallDecisionEngineService, + )?; + + logger::debug!("Decision engine health check successful"); + Ok(HealthState::Running) + } else { + logger::debug!("Decision engine health check not applicable"); + Ok(HealthState::NotApplicable) + } + } } diff --git a/crates/router/src/routes/health.rs b/crates/router/src/routes/health.rs index 7e9de917be3..f2ed05030da 100644 --- a/crates/router/src/routes/health.rs +++ b/crates/router/src/routes/health.rs @@ -108,6 +108,23 @@ async fn deep_health_check_func( logger::debug!("gRPC health check end"); + logger::debug!("Decision Engine health check begin"); + + #[cfg(feature = "dynamic_routing")] + let decision_engine_health_check = + state + .health_check_decision_engine() + .await + .map_err(|error| { + let message = error.to_string(); + error.change_context(errors::ApiErrorResponse::HealthCheckError { + component: "Decision Engine service", + message, + }) + })?; + + logger::debug!("Decision Engine health check end"); + logger::debug!("Opensearch health check begin"); #[cfg(feature = "olap")] @@ -144,6 +161,8 @@ async fn deep_health_check_func( outgoing_request: outgoing_check.into(), #[cfg(feature = "dynamic_routing")] grpc_health_check, + #[cfg(feature = "dynamic_routing")] + decision_engine: decision_engine_health_check.into(), }; Ok(api::ApplicationResponse::Json(response)) diff --git a/crates/storage_impl/src/errors.rs b/crates/storage_impl/src/errors.rs index 6d48fbcddac..5bab662687d 100644 --- a/crates/storage_impl/src/errors.rs +++ b/crates/storage_impl/src/errors.rs @@ -280,3 +280,9 @@ pub enum RecoveryError { #[error("Failed to fetch billing connector account id")] BillingMerchantConnectorAccountIdNotFound, } + +#[derive(Debug, Clone, thiserror::Error)] +pub enum HealthCheckDecisionEngineError { + #[error("Failed to establish Decision Engine connection")] + FailedToCallDecisionEngineService, +}