diff options
Diffstat (limited to 'grasp-audit/src/probe.rs')
| -rw-r--r-- | grasp-audit/src/probe.rs | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/grasp-audit/src/probe.rs b/grasp-audit/src/probe.rs index 4d8f31f..1a8687e 100644 --- a/grasp-audit/src/probe.rs +++ b/grasp-audit/src/probe.rs | |||
| @@ -213,16 +213,37 @@ pub async fn run_probe( | |||
| 213 | 213 | ||
| 214 | /// Fill all check names not yet present in `checks` as skipped with the | 214 | /// Fill all check names not yet present in `checks` as skipped with the |
| 215 | /// given reason, then return a finished ProbeReport. | 215 | /// given reason, then return a finished ProbeReport. |
| 216 | /// | ||
| 217 | /// The deadline fired before `$timed_out_name` could start. Diagnose | ||
| 218 | /// whether a single prior check dominated the budget (>50%) or whether | ||
| 219 | /// the relay was generally slow across multiple steps. | ||
| 216 | macro_rules! deadline_return { | 220 | macro_rules! deadline_return { |
| 217 | ($relay_url:expr, $timestamp:expr, $total_start:expr, $checks:expr, $timed_out_name:expr) => {{ | 221 | ($relay_url:expr, $timestamp:expr, $total_start:expr, $overall_secs:expr, $checks:expr, $timed_out_name:expr) => {{ |
| 218 | // Mark the step that hit the deadline as a timeout failure | 222 | let total_ms = $total_start.elapsed().as_millis() as u64; |
| 223 | let budget_ms = ($overall_secs as u64) * 1000; | ||
| 224 | |||
| 225 | // Find the single check that consumed the most time, if it took | ||
| 226 | // more than half the overall budget it is the likely culprit. | ||
| 227 | let slowest = $checks | ||
| 228 | .iter() | ||
| 229 | .filter(|c| !c.skipped) | ||
| 230 | .max_by_key(|c| c.duration_ms); | ||
| 231 | |||
| 232 | let error_msg = match slowest { | ||
| 233 | Some(c) if c.duration_ms > budget_ms / 2 => { | ||
| 234 | format!("overall timeout (likely caused by slow {})", c.name) | ||
| 235 | } | ||
| 236 | _ => "overall timeout (cumulative slowness across checks)".to_string(), | ||
| 237 | }; | ||
| 238 | |||
| 239 | // The step that couldn't start due to the deadline | ||
| 219 | $checks.push(ProbeCheck { | 240 | $checks.push(ProbeCheck { |
| 220 | name: $timed_out_name, | 241 | name: $timed_out_name, |
| 221 | passed: false, | 242 | passed: false, |
| 222 | skipped: false, | 243 | skipped: false, |
| 223 | duration_ms: $total_start.elapsed().as_millis() as u64, | 244 | duration_ms: 0, |
| 224 | detail: None, | 245 | detail: None, |
| 225 | error: Some("overall timeout".to_string()), | 246 | error: Some(error_msg), |
| 226 | }); | 247 | }); |
| 227 | // Skip all subsequent checks | 248 | // Skip all subsequent checks |
| 228 | let already: std::collections::HashSet<&str> = | 249 | let already: std::collections::HashSet<&str> = |
| @@ -237,7 +258,7 @@ pub async fn run_probe( | |||
| 237 | relay_url: $relay_url.to_string(), | 258 | relay_url: $relay_url.to_string(), |
| 238 | timestamp: $timestamp, | 259 | timestamp: $timestamp, |
| 239 | all_passed, | 260 | all_passed, |
| 240 | total_duration_ms: $total_start.elapsed().as_millis() as u64, | 261 | total_duration_ms: total_ms, |
| 241 | checks: $checks, | 262 | checks: $checks, |
| 242 | }; | 263 | }; |
| 243 | }}; | 264 | }}; |
| @@ -347,7 +368,7 @@ pub async fn run_probe( | |||
| 347 | // Step 1: connect_websocket | 368 | // Step 1: connect_websocket |
| 348 | // ============================================================ | 369 | // ============================================================ |
| 349 | if Instant::now() >= deadline { | 370 | if Instant::now() >= deadline { |
| 350 | deadline_return!(relay_url, timestamp, total_start, checks, "connect_websocket"); | 371 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "connect_websocket"); |
| 351 | } | 372 | } |
| 352 | let step1_start = Instant::now(); | 373 | let step1_start = Instant::now(); |
| 353 | let client_result = tokio::time::timeout( | 374 | let client_result = tokio::time::timeout( |
| @@ -405,7 +426,7 @@ pub async fn run_probe( | |||
| 405 | // ============================================================ | 426 | // ============================================================ |
| 406 | { | 427 | { |
| 407 | if Instant::now() >= deadline { | 428 | if Instant::now() >= deadline { |
| 408 | deadline_return!(relay_url, timestamp, total_start, checks, "nip11_fetch"); | 429 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "nip11_fetch"); |
| 409 | } | 430 | } |
| 410 | let step2_start = Instant::now(); | 431 | let step2_start = Instant::now(); |
| 411 | let http_client = reqwest::Client::new(); | 432 | let http_client = reqwest::Client::new(); |
| @@ -475,7 +496,7 @@ pub async fn run_probe( | |||
| 475 | let mut write_succeeded = false; | 496 | let mut write_succeeded = false; |
| 476 | 497 | ||
| 477 | if Instant::now() >= deadline { | 498 | if Instant::now() >= deadline { |
| 478 | deadline_return!(relay_url, timestamp, total_start, checks, "publish_events"); | 499 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "publish_events"); |
| 479 | } | 500 | } |
| 480 | 501 | ||
| 481 | if read_only { | 502 | if read_only { |
| @@ -537,7 +558,7 @@ pub async fn run_probe( | |||
| 537 | // ============================================================ | 558 | // ============================================================ |
| 538 | if write_succeeded { | 559 | if write_succeeded { |
| 539 | if Instant::now() >= deadline { | 560 | if Instant::now() >= deadline { |
| 540 | deadline_return!(relay_url, timestamp, total_start, checks, "git_repo_initialised"); | 561 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "git_repo_initialised"); |
| 541 | } | 562 | } |
| 542 | let step4_start = Instant::now(); | 563 | let step4_start = Instant::now(); |
| 543 | let poll_url = format!("{}/info/refs?service=git-upload-pack", clone_url); | 564 | let poll_url = format!("{}/info/refs?service=git-upload-pack", clone_url); |
| @@ -590,7 +611,7 @@ pub async fn run_probe( | |||
| 590 | // ============================================================ | 611 | // ============================================================ |
| 591 | if write_succeeded { | 612 | if write_succeeded { |
| 592 | if Instant::now() >= deadline { | 613 | if Instant::now() >= deadline { |
| 593 | deadline_return!(relay_url, timestamp, total_start, checks, "git_push"); | 614 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "git_push"); |
| 594 | } | 615 | } |
| 595 | let step5_start = Instant::now(); | 616 | let step5_start = Instant::now(); |
| 596 | let push_result = try_push(&local_repo_path); | 617 | let push_result = try_push(&local_repo_path); |
| @@ -671,7 +692,7 @@ pub async fn run_probe( | |||
| 671 | // ---- Write path ---- | 692 | // ---- Write path ---- |
| 672 | // Step 6a: git_fetch_refs — just verify the endpoint returns 200 | 693 | // Step 6a: git_fetch_refs — just verify the endpoint returns 200 |
| 673 | if Instant::now() >= deadline { | 694 | if Instant::now() >= deadline { |
| 674 | deadline_return!(relay_url, timestamp, total_start, checks, "git_fetch_refs"); | 695 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "git_fetch_refs"); |
| 675 | } | 696 | } |
| 676 | let refs_url = format!("{}/info/refs?service=git-upload-pack", clone_url); | 697 | let refs_url = format!("{}/info/refs?service=git-upload-pack", clone_url); |
| 677 | let http_client = reqwest::Client::new(); | 698 | let http_client = reqwest::Client::new(); |
| @@ -799,7 +820,7 @@ pub async fn run_probe( | |||
| 799 | 820 | ||
| 800 | // In read-only mode: first check that at least one announcement exists | 821 | // In read-only mode: first check that at least one announcement exists |
| 801 | if Instant::now() >= deadline { | 822 | if Instant::now() >= deadline { |
| 802 | deadline_return!(relay_url, timestamp, total_start, checks, "serves_latest_announcement"); | 823 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "serves_latest_announcement"); |
| 803 | } | 824 | } |
| 804 | let filter = Filter::new().kind(Kind::GitRepoAnnouncement).limit(1); | 825 | let filter = Filter::new().kind(Kind::GitRepoAnnouncement).limit(1); |
| 805 | let existing = client | 826 | let existing = client |
| @@ -880,7 +901,7 @@ pub async fn run_probe( | |||
| 880 | }); | 901 | }); |
| 881 | 902 | ||
| 882 | if Instant::now() >= deadline { | 903 | if Instant::now() >= deadline { |
| 883 | deadline_return!(relay_url, timestamp, total_start, checks, "git_fetch_refs"); | 904 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "git_fetch_refs"); |
| 884 | } | 905 | } |
| 885 | let step6_start = Instant::now(); | 906 | let step6_start = Instant::now(); |
| 886 | let refs_url = format!("{}/info/refs?service=git-upload-pack", fetch_url); | 907 | let refs_url = format!("{}/info/refs?service=git-upload-pack", fetch_url); |