Skip to main content

paas_server/application/
status.rs

1use actix_web::web::Data;
2use actix_web::{HttpResponse, Responder};
3use chrono::Utc;
4use log::error;
5use paas_api::config::PAASConfig;
6use paas_api::status::{StatusResponse, SystemId, VersionInfo};
7use serde::Serialize;
8use std::fs;
9
10use crate::session_storage::SessionStorage;
11
12#[derive(Serialize)]
13pub struct HealthCheckResponse {
14    pub status: String,
15    pub timestamp: chrono::DateTime<chrono::Utc>,
16    pub checks: HealthChecks,
17}
18
19#[derive(Serialize)]
20pub struct HealthChecks {
21    pub session_storage: CheckStatus,
22}
23
24#[derive(Serialize)]
25pub struct CheckStatus {
26    pub status: String,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub message: Option<String>,
29}
30
31pub async fn health(session_storage: Data<Box<dyn SessionStorage>>) -> impl Responder {
32    let mut overall_healthy = true;
33
34    // Check session storage connectivity
35    let storage_check = match check_session_storage(session_storage.get_ref().as_ref()).await {
36        Ok(_) => CheckStatus {
37            status: "healthy".to_string(),
38            message: None,
39        },
40        Err(e) => {
41            overall_healthy = false;
42            error!("Session storage health check failed: {:?}", e);
43            CheckStatus {
44                status: "unhealthy".to_string(),
45                message: Some(format!("Session storage check failed: {:?}", e)),
46            }
47        }
48    };
49
50    let response = HealthCheckResponse {
51        status: if overall_healthy {
52            "healthy"
53        } else {
54            "unhealthy"
55        }
56        .to_string(),
57        timestamp: Utc::now(),
58        checks: HealthChecks {
59            session_storage: storage_check,
60        },
61    };
62
63    if overall_healthy {
64        HttpResponse::Ok().json(response)
65    } else {
66        HttpResponse::ServiceUnavailable().json(response)
67    }
68}
69
70async fn check_session_storage(storage: &dyn SessionStorage) -> Result<(), std::fmt::Error> {
71    // Try to perform a lightweight operation to verify storage is accessible
72    // For Redis: this will check connection pool health
73    // For InMemory: this will verify the mutex isn't poisoned
74    storage.get_all_sessions().map(|_| ())
75}
76
77pub async fn status(paas_system_id: Data<SystemId>) -> impl Responder {
78    HttpResponse::Ok().json(StatusResponse {
79        system_id: paas_system_id.to_string(),
80        timestamp: Utc::now(),
81        version_info: VersionInfo::default(),
82    })
83}
84
85pub fn load_paas_config(config_file: &str) -> PAASConfig {
86    let file_content =
87        fs::read_to_string(config_file).expect("Failed to read public PAAS config file");
88    let config: PAASConfig =
89        serde_json::from_str(&file_content).expect("Failed to parse public PAAS config file");
90
91    config
92}
93
94pub async fn config(paas_config: Data<PAASConfig>) -> impl Responder {
95    HttpResponse::Ok().json(paas_config)
96}