✅ Validation Results: - PPO training: 24.2s (1 epoch, 950 samples, dim=225) - Feature extraction: 105μs/bar (9.5x faster than target) - Model checkpoint: 293KB (147KB actor + 146KB critic) - GPU memory: 145MB used (96.4% headroom) - Zero dimension mismatches 📊 Success Criteria (5/5): ✅ Feature dimension = 225 (Wave C 201 + Wave D 24) ✅ Model state_dim = 225 ✅ Training completed without errors ✅ Checkpoint saved successfully ✅ No dimension mismatch errors 📁 Training Data Ready: - ES.FUT: 2.9MB, 180 days - NQ.FUT: 4.4MB, 180 days - 6E.FUT: 2.8MB, 180 days - ZN.FUT: 65KB, 90 days (clean) 🚀 Next: Full production model retraining (4 models, ~10min GPU time) 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
134 lines
3.5 KiB
Rust
134 lines
3.5 KiB
Rust
//! Health check endpoints for API Gateway service
|
|
//!
|
|
//! Provides HTTP-based health and readiness endpoints for Kubernetes probes.
|
|
//! These endpoints don't require authentication to allow load balancers and
|
|
//! orchestrators to check service health.
|
|
|
|
use axum::{extract::State, http::StatusCode, routing::get, Json, Router};
|
|
use serde::Serialize;
|
|
use std::sync::Arc;
|
|
use sqlx::PgPool;
|
|
use redis::aio::ConnectionManager;
|
|
|
|
/// Health status response
|
|
#[derive(Serialize)]
|
|
pub struct HealthResponse {
|
|
/// Service status
|
|
pub status: &'static str,
|
|
/// Service name
|
|
pub service: &'static str,
|
|
/// Service version
|
|
pub version: &'static str,
|
|
}
|
|
|
|
/// Detailed health status with dependency checks
|
|
#[derive(Serialize)]
|
|
pub struct DetailedHealthResponse {
|
|
/// Service status
|
|
pub status: &'static str,
|
|
/// Service name
|
|
pub service: &'static str,
|
|
/// Service version
|
|
pub version: &'static str,
|
|
/// Database connectivity
|
|
pub database: bool,
|
|
/// Redis connectivity
|
|
pub redis: bool,
|
|
}
|
|
|
|
/// Shared health check state
|
|
#[derive(Clone)]
|
|
pub struct HealthState {
|
|
/// PostgreSQL connection pool
|
|
pub db_pool: Option<PgPool>,
|
|
/// Redis connection manager
|
|
pub redis: Option<ConnectionManager>,
|
|
}
|
|
|
|
/// Creates the health check router with /health and /ready endpoints
|
|
pub fn health_router(state: HealthState) -> Router {
|
|
Router::new()
|
|
.route("/health", get(health_check))
|
|
.route("/ready", get(readiness_check))
|
|
.with_state(Arc::new(state))
|
|
}
|
|
|
|
/// Liveness probe - indicates service is running
|
|
/// Returns 200 OK if the service process is alive
|
|
async fn health_check() -> Json<HealthResponse> {
|
|
Json(HealthResponse {
|
|
status: "healthy",
|
|
service: "api_gateway",
|
|
version: env!("CARGO_PKG_VERSION"),
|
|
})
|
|
}
|
|
|
|
/// Readiness probe - indicates service is ready to accept requests
|
|
/// Checks database and Redis connectivity
|
|
async fn readiness_check(
|
|
State(state): State<Arc<HealthState>>,
|
|
) -> Result<Json<DetailedHealthResponse>, StatusCode> {
|
|
let mut db_ok = false;
|
|
let mut redis_ok = false;
|
|
|
|
// Check database connectivity
|
|
if let Some(ref pool) = state.db_pool {
|
|
db_ok = sqlx::query("SELECT 1")
|
|
.fetch_one(pool)
|
|
.await
|
|
.is_ok();
|
|
}
|
|
|
|
// Check Redis connectivity
|
|
if let Some(ref mut redis_conn) = state.redis.clone() {
|
|
use redis::AsyncCommands;
|
|
redis_ok = redis_conn.ping::<()>().await.is_ok();
|
|
}
|
|
|
|
// Service is ready only if all dependencies are healthy
|
|
let is_ready = db_ok && redis_ok;
|
|
let status = if is_ready { "ready" } else { "not_ready" };
|
|
let http_status = if is_ready {
|
|
StatusCode::OK
|
|
} else {
|
|
StatusCode::SERVICE_UNAVAILABLE
|
|
};
|
|
|
|
let response = DetailedHealthResponse {
|
|
status,
|
|
service: "api_gateway",
|
|
version: env!("CARGO_PKG_VERSION"),
|
|
database: db_ok,
|
|
redis: redis_ok,
|
|
};
|
|
|
|
if is_ready {
|
|
Ok(Json(response))
|
|
} else {
|
|
Err(http_status)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn test_health_check() {
|
|
let response = health_check().await;
|
|
assert_eq!(response.status, "healthy");
|
|
assert_eq!(response.service, "api_gateway");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_readiness_check_without_deps() {
|
|
let state = Arc::new(HealthState {
|
|
db_pool: None,
|
|
redis: None,
|
|
});
|
|
|
|
let result = readiness_check(State(state)).await;
|
|
assert!(result.is_err());
|
|
}
|
|
}
|