upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/grasp-audit/src/probe.rs
diff options
context:
space:
mode:
Diffstat (limited to 'grasp-audit/src/probe.rs')
-rw-r--r--grasp-audit/src/probe.rs47
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);