feat(v2): introduce configs and health endpoints for v2 (#8835)

This commit is contained in:
Hrithikesh
2025-08-08 18:13:15 +05:30
committed by GitHub
parent 951412f33b
commit 8bbb76840b
6 changed files with 78 additions and 5 deletions

View File

@ -14,6 +14,7 @@ pub struct RouterHealthCheckResponse {
pub grpc_health_check: HealthCheckMap, pub grpc_health_check: HealthCheckMap,
#[cfg(feature = "dynamic_routing")] #[cfg(feature = "dynamic_routing")]
pub decision_engine: bool, pub decision_engine: bool,
pub unified_connector_service: Option<bool>,
} }
impl common_utils::events::ApiEventMetric for RouterHealthCheckResponse {} impl common_utils::events::ApiEventMetric for RouterHealthCheckResponse {}

View File

@ -40,6 +40,10 @@ pub trait HealthCheckInterface {
async fn health_check_decision_engine( async fn health_check_decision_engine(
&self, &self,
) -> CustomResult<HealthState, errors::HealthCheckDecisionEngineError>; ) -> CustomResult<HealthState, errors::HealthCheckDecisionEngineError>;
async fn health_check_unified_connector_service(
&self,
) -> CustomResult<HealthState, errors::HealthCheckUnifiedConnectorServiceError>;
} }
#[async_trait::async_trait] #[async_trait::async_trait]
@ -210,4 +214,19 @@ impl HealthCheckInterface for app::SessionState {
Ok(HealthState::NotApplicable) Ok(HealthState::NotApplicable)
} }
} }
async fn health_check_unified_connector_service(
&self,
) -> CustomResult<HealthState, errors::HealthCheckUnifiedConnectorServiceError> {
if let Some(_ucs_client) = &self.grpc_client.unified_connector_service_client {
// For now, we'll just check if the client exists and is configured
// In the future, this could be enhanced to make an actual health check call
// to the unified connector service if it supports health check endpoints
logger::debug!("Unified Connector Service client is configured and available");
Ok(HealthState::Running)
} else {
logger::debug!("Unified Connector Service client not configured");
Ok(HealthState::NotApplicable)
}
}
} }

View File

@ -565,6 +565,7 @@ impl AppState {
pub struct Health; pub struct Health;
#[cfg(feature = "v1")]
impl Health { impl Health {
pub fn server(state: AppState) -> Scope { pub fn server(state: AppState) -> Scope {
web::scope("health") web::scope("health")
@ -574,6 +575,16 @@ impl Health {
} }
} }
#[cfg(feature = "v2")]
impl Health {
pub fn server(state: AppState) -> Scope {
web::scope("/v2/health")
.app_data(web::Data::new(state))
.service(web::resource("").route(web::get().to(health)))
.service(web::resource("/ready").route(web::get().to(deep_health_check)))
}
}
#[cfg(feature = "dummy_connector")] #[cfg(feature = "dummy_connector")]
pub struct DummyConnector; pub struct DummyConnector;
@ -1867,7 +1878,7 @@ impl Webhooks {
pub struct Configs; pub struct Configs;
#[cfg(any(feature = "olap", feature = "oltp"))] #[cfg(all(feature = "v1", any(feature = "olap", feature = "oltp")))]
impl Configs { impl Configs {
pub fn server(config: AppState) -> Scope { pub fn server(config: AppState) -> Scope {
web::scope("/configs") web::scope("/configs")
@ -1882,6 +1893,21 @@ impl Configs {
} }
} }
#[cfg(all(feature = "v2", any(feature = "olap", feature = "oltp")))]
impl Configs {
pub fn server(config: AppState) -> Scope {
web::scope("/v2/configs")
.app_data(web::Data::new(config))
.service(web::resource("/").route(web::post().to(config_key_create)))
.service(
web::resource("/{key}")
.route(web::get().to(config_key_retrieve))
.route(web::post().to(config_key_update))
.route(web::delete().to(config_key_delete)),
)
}
}
pub struct ApplePayCertificatesMigration; pub struct ApplePayCertificatesMigration;
#[cfg(all(feature = "olap", feature = "v1"))] #[cfg(all(feature = "olap", feature = "v1"))]

View File

@ -8,6 +8,11 @@ use crate::{
types::api as api_types, types::api as api_types,
}; };
#[cfg(feature = "v1")]
const ADMIN_API_AUTH: auth::AdminApiAuth = auth::AdminApiAuth;
#[cfg(feature = "v2")]
const ADMIN_API_AUTH: auth::V2AdminApiAuth = auth::V2AdminApiAuth;
#[instrument(skip_all, fields(flow = ?Flow::CreateConfigKey))] #[instrument(skip_all, fields(flow = ?Flow::CreateConfigKey))]
pub async fn config_key_create( pub async fn config_key_create(
state: web::Data<AppState>, state: web::Data<AppState>,
@ -23,7 +28,7 @@ pub async fn config_key_create(
&req, &req,
payload, payload,
|state, _, data, _| configs::set_config(state, data), |state, _, data, _| configs::set_config(state, data),
&auth::AdminApiAuth, &ADMIN_API_AUTH,
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -43,7 +48,7 @@ pub async fn config_key_retrieve(
&req, &req,
&key, &key,
|state, _, key, _| configs::read_config(state, key), |state, _, key, _| configs::read_config(state, key),
&auth::AdminApiAuth, &ADMIN_API_AUTH,
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -66,7 +71,7 @@ pub async fn config_key_update(
&req, &req,
&payload, &payload,
|state, _, payload, _| configs::update_config(state, payload), |state, _, payload, _| configs::update_config(state, payload),
&auth::AdminApiAuth, &ADMIN_API_AUTH,
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await
@ -87,7 +92,7 @@ pub async fn config_key_delete(
&req, &req,
key, key,
|state, _, key, _| configs::config_delete(state, key), |state, _, key, _| configs::config_delete(state, key),
&auth::AdminApiAuth, &ADMIN_API_AUTH,
api_locking::LockAction::NotApplicable, api_locking::LockAction::NotApplicable,
) )
.await .await

View File

@ -150,6 +150,21 @@ async fn deep_health_check_func(
logger::debug!("Outgoing Request health check end"); logger::debug!("Outgoing Request health check end");
logger::debug!("Unified Connector Service health check begin");
let unified_connector_service_status = state
.health_check_unified_connector_service()
.await
.map_err(|error| {
let message = error.to_string();
error.change_context(errors::ApiErrorResponse::HealthCheckError {
component: "Unified Connector Service",
message,
})
})?;
logger::debug!("Unified Connector Service health check end");
let response = RouterHealthCheckResponse { let response = RouterHealthCheckResponse {
database: db_status.into(), database: db_status.into(),
redis: redis_status.into(), redis: redis_status.into(),
@ -163,6 +178,7 @@ async fn deep_health_check_func(
grpc_health_check, grpc_health_check,
#[cfg(feature = "dynamic_routing")] #[cfg(feature = "dynamic_routing")]
decision_engine: decision_engine_health_check.into(), decision_engine: decision_engine_health_check.into(),
unified_connector_service: unified_connector_service_status.into(),
}; };
Ok(api::ApplicationResponse::Json(response)) Ok(api::ApplicationResponse::Json(response))

View File

@ -294,3 +294,9 @@ pub enum HealthCheckDecisionEngineError {
#[error("Failed to establish Decision Engine connection")] #[error("Failed to establish Decision Engine connection")]
FailedToCallDecisionEngineService, FailedToCallDecisionEngineService,
} }
#[derive(Debug, Clone, thiserror::Error)]
pub enum HealthCheckUnifiedConnectorServiceError {
#[error("Failed to establish Unified Connector Service connection")]
FailedToCallUnifiedConnectorService,
}