Skip to main content

hypercall_admin/monitoring/
instruments.rs

1//! Instruments cache reload admin endpoint.
2
3use axum::{extract::State, http::StatusCode, response::IntoResponse};
4use serde::Serialize;
5
6use crate::state::AdminState;
7use hypercall_runtime_api::sonic_json::SonicJson;
8
9/// Response for /monitoring/reload_instruments_cache endpoint
10#[derive(Debug, Serialize, utoipa::ToSchema)]
11pub struct ReloadInstrumentsCacheResponse {
12    /// Whether the reload was successful
13    pub success: bool,
14    /// Number of instruments before reload
15    pub count_before: usize,
16    /// Number of instruments after reload
17    pub count_after: usize,
18    /// Error message if any
19    pub error: Option<String>,
20}
21
22/// POST /monitoring/reload_instruments_cache - Force reload instruments cache from database
23///
24/// This endpoint forces the instruments cache to reload from the database.
25/// Useful when the cache gets out of sync (e.g., after fresh deployment with empty DB
26/// followed by CatalogManager creating instruments).
27#[utoipa::path(
28    post,
29    path = "/monitoring/reload_instruments_cache",
30    responses(
31        (status = 200, description = "Cache reload result", body = ReloadInstrumentsCacheResponse),
32        (status = 401, description = "Invalid or missing X-Admin-Key header"),
33        (status = 500, description = "Failed to reload cache")
34    ),
35    tag = "Monitoring",
36    security(("admin_key" = []))
37)]
38pub async fn reload_instruments_cache(State(app_state): State<AdminState>) -> impl IntoResponse {
39    let count_before = app_state.instruments_cache.len().await;
40
41    match app_state
42        .instruments_cache
43        .reload_from_db(app_state.db.as_ref())
44        .await
45    {
46        Ok(()) => {
47            let count_after = app_state.instruments_cache.len().await;
48            tracing::info!(
49                "Instruments cache reloaded: {} -> {} instruments",
50                count_before,
51                count_after
52            );
53            (
54                StatusCode::OK,
55                SonicJson(ReloadInstrumentsCacheResponse {
56                    success: true,
57                    count_before,
58                    count_after,
59                    error: None,
60                }),
61            )
62                .into_response()
63        }
64        Err(e) => {
65            tracing::error!("Failed to reload instruments cache: {}", e);
66            (
67                StatusCode::INTERNAL_SERVER_ERROR,
68                SonicJson(ReloadInstrumentsCacheResponse {
69                    success: false,
70                    count_before,
71                    count_after: count_before, // unchanged
72                    error: Some(format!("Failed to reload: {}", e)),
73                }),
74            )
75                .into_response()
76        }
77    }
78}