// SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 use super::{service_v2, RouteDoc}; use axum::{http::Method, http::StatusCode, response::IntoResponse, routing::get, Json, Router}; use dynamo_runtime::instances::list_all_instances; use serde_json::json; use std::sync::Arc; pub fn health_check_router( state: Arc, path: Option, ) -> (Vec, Router) { let health_path = path.unwrap_or_else(|| "/health".to_string()); let docs: Vec = vec![RouteDoc::new(Method::GET, &health_path)]; let router = Router::new() .route(&health_path, get(health_handler)) .with_state(state); (docs, router) } pub fn live_check_router( state: Arc, path: Option, ) -> (Vec, Router) { let live_path = path.unwrap_or_else(|| "/live".to_string()); let docs: Vec = vec![RouteDoc::new(Method::GET, &live_path)]; let router = Router::new() .route(&live_path, get(live_handler)) .with_state(state); (docs, router) } async fn live_handler( axum::extract::State(_state): axum::extract::State>, ) -> impl IntoResponse { ( StatusCode::OK, Json(json!({ "status": "live", "message": "Service is live" })), ) } async fn health_handler( axum::extract::State(state): axum::extract::State>, ) -> impl IntoResponse { let model_entries = state.manager().get_model_entries(); let instances = if let Some(etcd_client) = state.etcd_client() { match list_all_instances(etcd_client).await { Ok(instances) => instances, Err(err) => { tracing::warn!("Failed to fetch instances from etcd: {}", err); vec![] } } } else { vec![] }; if model_entries.is_empty() { ( StatusCode::SERVICE_UNAVAILABLE, Json(json!({ "status": "unhealthy", "message": "No endpoints available", "instances": instances })), ) } else { let endpoints: Vec = model_entries .iter() .map(|entry| entry.endpoint_id.as_url()) .collect(); ( StatusCode::OK, Json(json!({ "status": "healthy", "endpoints": endpoints, "instances": instances })), ) } }