diff options
| -rw-r--r-- | grasp-audit/src/bin/grasp-audit.rs | 36 | ||||
| -rw-r--r-- | grasp-audit/src/probe.rs | 20 |
2 files changed, 51 insertions, 5 deletions
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<()> { | |||
| 102 | None | 102 | None |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | // Overall probe timeout: min(20s, watch_interval) to prevent | ||
| 106 | // overlapping runs under --watch or cron scheduling. | ||
| 107 | let overall_secs = match watch { | ||
| 108 | Some(interval) => interval.min(20), | ||
| 109 | None => 20, | ||
| 110 | }; | ||
| 111 | |||
| 105 | if let Some(interval) = watch { | 112 | if let Some(interval) = watch { |
| 106 | let mut run = 1u64; | 113 | let mut run = 1u64; |
| 107 | loop { | 114 | loop { |
| 108 | if !json { | 115 | if !json { |
| 109 | println!("\n[Run {}]", run); | 116 | println!("\n[Run {}]", run); |
| 110 | } | 117 | } |
| 111 | let report = | 118 | let start = std::time::Instant::now(); |
| 112 | grasp_audit::probe::run_probe(&relay, keys.clone(), read_only, timeout) | 119 | let report = tokio::time::timeout( |
| 113 | .await; | 120 | Duration::from_secs(overall_secs), |
| 121 | grasp_audit::probe::run_probe(&relay, keys.clone(), read_only, timeout), | ||
| 122 | ) | ||
| 123 | .await | ||
| 124 | .unwrap_or_else(|_| { | ||
| 125 | grasp_audit::probe::ProbeReport::overall_timeout( | ||
| 126 | &relay, | ||
| 127 | start.elapsed().as_millis() as u64, | ||
| 128 | ) | ||
| 129 | }); | ||
| 114 | if json { | 130 | if json { |
| 115 | report.print_json(); | 131 | report.print_json(); |
| 116 | } else { | 132 | } else { |
| @@ -120,8 +136,18 @@ async fn main() -> Result<()> { | |||
| 120 | tokio::time::sleep(Duration::from_secs(interval)).await; | 136 | tokio::time::sleep(Duration::from_secs(interval)).await; |
| 121 | } | 137 | } |
| 122 | } else { | 138 | } else { |
| 123 | let report = | 139 | let start = std::time::Instant::now(); |
| 124 | grasp_audit::probe::run_probe(&relay, keys, read_only, timeout).await; | 140 | let report = tokio::time::timeout( |
| 141 | Duration::from_secs(overall_secs), | ||
| 142 | grasp_audit::probe::run_probe(&relay, keys, read_only, timeout), | ||
| 143 | ) | ||
| 144 | .await | ||
| 145 | .unwrap_or_else(|_| { | ||
| 146 | grasp_audit::probe::ProbeReport::overall_timeout( | ||
| 147 | &relay, | ||
| 148 | start.elapsed().as_millis() as u64, | ||
| 149 | ) | ||
| 150 | }); | ||
| 125 | if json { | 151 | if json { |
| 126 | report.print_json(); | 152 | report.print_json(); |
| 127 | } else { | 153 | } 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 { | |||
| 124 | } | 124 | } |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | impl ProbeReport { | ||
| 128 | /// Build a synthetic report for when the overall probe timeout fires. | ||
| 129 | pub fn overall_timeout(relay_url: &str, duration_ms: u64) -> Self { | ||
| 130 | ProbeReport { | ||
| 131 | relay_url: relay_url.to_string(), | ||
| 132 | timestamp: now_iso8601(), | ||
| 133 | all_passed: false, | ||
| 134 | total_duration_ms: duration_ms, | ||
| 135 | checks: vec![ProbeCheck { | ||
| 136 | name: "overall_timeout", | ||
| 137 | passed: false, | ||
| 138 | skipped: false, | ||
| 139 | duration_ms, | ||
| 140 | detail: None, | ||
| 141 | error: Some("probe exceeded overall timeout".to_string()), | ||
| 142 | }], | ||
| 143 | } | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 127 | // ============================================================ | 147 | // ============================================================ |
| 128 | // Helpers | 148 | // Helpers |
| 129 | // ============================================================ | 149 | // ============================================================ |