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,
#[cfg(feature = "dynamic_routing")]
pub decision_engine: bool,
pub unified_connector_service: Option<bool>,
}
impl common_utils::events::ApiEventMetric for RouterHealthCheckResponse {}

View File

@ -40,6 +40,10 @@ pub trait HealthCheckInterface {
async fn health_check_decision_engine(
&self,
) -> CustomResult<HealthState, errors::HealthCheckDecisionEngineError>;
async fn health_check_unified_connector_service(
&self,
) -> CustomResult<HealthState, errors::HealthCheckUnifiedConnectorServiceError>;
}
#[async_trait::async_trait]
@ -210,4 +214,19 @@ impl HealthCheckInterface for app::SessionState {
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;
#[cfg(feature = "v1")]
impl Health {
pub fn server(state: AppState) -> Scope {
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")]
pub struct DummyConnector;
@ -1867,7 +1878,7 @@ impl Webhooks {
pub struct Configs;
#[cfg(any(feature = "olap", feature = "oltp"))]
#[cfg(all(feature = "v1", any(feature = "olap", feature = "oltp")))]
impl Configs {
pub fn server(config: AppState) -> Scope {
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;
#[cfg(all(feature = "olap", feature = "v1"))]

View File

@ -8,6 +8,11 @@ use crate::{
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))]
pub async fn config_key_create(
state: web::Data<AppState>,
@ -23,7 +28,7 @@ pub async fn config_key_create(
&req,
payload,
|state, _, data, _| configs::set_config(state, data),
&auth::AdminApiAuth,
&ADMIN_API_AUTH,
api_locking::LockAction::NotApplicable,
)
.await
@ -43,7 +48,7 @@ pub async fn config_key_retrieve(
&req,
&key,
|state, _, key, _| configs::read_config(state, key),
&auth::AdminApiAuth,
&ADMIN_API_AUTH,
api_locking::LockAction::NotApplicable,
)
.await
@ -66,7 +71,7 @@ pub async fn config_key_update(
&req,
&payload,
|state, _, payload, _| configs::update_config(state, payload),
&auth::AdminApiAuth,
&ADMIN_API_AUTH,
api_locking::LockAction::NotApplicable,
)
.await
@ -87,7 +92,7 @@ pub async fn config_key_delete(
&req,
key,
|state, _, key, _| configs::config_delete(state, key),
&auth::AdminApiAuth,
&ADMIN_API_AUTH,
api_locking::LockAction::NotApplicable,
)
.await

View File

@ -150,6 +150,21 @@ async fn deep_health_check_func(
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 {
database: db_status.into(),
redis: redis_status.into(),
@ -163,6 +178,7 @@ async fn deep_health_check_func(
grpc_health_check,
#[cfg(feature = "dynamic_routing")]
decision_engine: decision_engine_health_check.into(),
unified_connector_service: unified_connector_service_status.into(),
};
Ok(api::ApplicationResponse::Json(response))

View File

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