From e435f7d7b4ad4e4b1d3c21c35df5f41ffd642376 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 26 May 2026 18:01:30 +0530 Subject: Add HTTP health endpoint on /health and /api/mirror-health - New axum-based health server on port 7335 (configurable via health_port) - Reports status, uptime, cycle_count, last_cycle_ok as JSON - Status is 'ok' on startup and after successful cycles, 'degraded' after failures - Config: storage.health_port defaults to 7335 - Spawned alongside daemon loop, independent of mirror cycles --- src/main.rs | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs index b709d44..494342c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod db; mod discovery; mod git_mirror; mod health; +mod http_health; mod nostr_mirror; mod signing; @@ -70,6 +71,24 @@ async fn run_daemon(config: config::ResolvedConfig, db: db::MirrorDb) -> Result< let db = Arc::new(db); let config = Arc::new(config); + let (cycle_count_tx, cycle_count_rx) = tokio::sync::watch::channel(0u64); + let (last_cycle_ok_tx, last_cycle_ok_rx) = tokio::sync::watch::channel(true); + + let health_state = Arc::new(http_health::HealthState { + started_at: std::time::Instant::now(), + cycle_count: cycle_count_rx, + last_cycle_ok: last_cycle_ok_rx, + db_path: config.storage.database.display().to_string(), + }); + + let health_port = config.storage.health_port; + let health_state_clone = health_state.clone(); + tokio::spawn(async move { + if let Err(e) = http_health::start_health_server(health_port, health_state_clone).await { + tracing::error!(error = %e, "health server failed"); + } + }); + let servers = health::verify_all_servers(&config.servers.known).await; let healthy: Vec<_> = servers .values() @@ -101,19 +120,28 @@ async fn run_daemon(config: config::ResolvedConfig, db: db::MirrorDb) -> Result< config.discovery.poll_interval_secs ); + let mut cycle_count: u64 = 0; + loop { tokio::select! { _ = interval.tick() => { - if let Err(e) = mirror_cycle( + let result = mirror_cycle( &config, &db, &nostr_client, &mirror, &nostr_mirror, &healthy, - ).await { - tracing::error!(error = %e, "mirror cycle failed"); + ).await; + + match &result { + Ok(()) => tracing::info!("mirror cycle complete"), + Err(e) => tracing::error!(error = %e, "mirror cycle failed"), } + + cycle_count += 1; + let _ = cycle_count_tx.send(cycle_count); + let _ = last_cycle_ok_tx.send(result.is_ok()); } _ = tokio::signal::ctrl_c() => { tracing::info!("shutting down"); -- cgit v1.2.3