From 6007647e37344bcc3e8ade6500ed5dbb11d302e0 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 25 Feb 2026 13:55:52 +0000 Subject: add overall probe timeout of min(20s, watch_interval) to prevent overlapping runs --- grasp-audit/src/bin/grasp-audit.rs | 36 +++++++++++++++++++++++++++++++----- grasp-audit/src/probe.rs | 20 ++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) (limited to 'grasp-audit/src') diff --git a/grasp-audit/src/bin/grasp-audit.rs b/grasp-audit/src/bin/grasp-audit.rs index 3d5b107..f56fc44 100644 --- a/grasp-audit/src/bin/grasp-audit.rs +++ b/grasp-audit/src/bin/grasp-audit.rs @@ -102,15 +102,31 @@ async fn main() -> Result<()> { None }; + // Overall probe timeout: min(20s, watch_interval) to prevent + // overlapping runs under --watch or cron scheduling. + let overall_secs = match watch { + Some(interval) => interval.min(20), + None => 20, + }; + if let Some(interval) = watch { let mut run = 1u64; loop { if !json { println!("\n[Run {}]", run); } - let report = - grasp_audit::probe::run_probe(&relay, keys.clone(), read_only, timeout) - .await; + let start = std::time::Instant::now(); + let report = tokio::time::timeout( + Duration::from_secs(overall_secs), + grasp_audit::probe::run_probe(&relay, keys.clone(), read_only, timeout), + ) + .await + .unwrap_or_else(|_| { + grasp_audit::probe::ProbeReport::overall_timeout( + &relay, + start.elapsed().as_millis() as u64, + ) + }); if json { report.print_json(); } else { @@ -120,8 +136,18 @@ async fn main() -> Result<()> { tokio::time::sleep(Duration::from_secs(interval)).await; } } else { - let report = - grasp_audit::probe::run_probe(&relay, keys, read_only, timeout).await; + let start = std::time::Instant::now(); + let report = tokio::time::timeout( + Duration::from_secs(overall_secs), + grasp_audit::probe::run_probe(&relay, keys, read_only, timeout), + ) + .await + .unwrap_or_else(|_| { + grasp_audit::probe::ProbeReport::overall_timeout( + &relay, + start.elapsed().as_millis() as u64, + ) + }); if json { report.print_json(); } else { diff --git a/grasp-audit/src/probe.rs b/grasp-audit/src/probe.rs index 7158d42..0dca74c 100644 --- a/grasp-audit/src/probe.rs +++ b/grasp-audit/src/probe.rs @@ -124,6 +124,26 @@ impl ProbeReport { } } +impl ProbeReport { + /// Build a synthetic report for when the overall probe timeout fires. + pub fn overall_timeout(relay_url: &str, duration_ms: u64) -> Self { + ProbeReport { + relay_url: relay_url.to_string(), + timestamp: now_iso8601(), + all_passed: false, + total_duration_ms: duration_ms, + checks: vec![ProbeCheck { + name: "overall_timeout", + passed: false, + skipped: false, + duration_ms, + detail: None, + error: Some("probe exceeded overall timeout".to_string()), + }], + } + } +} + // ============================================================ // Helpers // ============================================================ -- cgit v1.2.3