From 42024a9fc33b1dc98991d186fea946c70857d7a2 Mon Sep 17 00:00:00 2001 From: nate Date: Wed, 18 Mar 2026 18:50:16 +0400 Subject: [PATCH] fix: use monitor-side checked_at timestamp instead of coordinator arrival time --- apps/api/src/routes/pings.ts | 5 ++++- apps/monitor/src/runner.rs | 6 ++++++ apps/monitor/src/types.rs | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/api/src/routes/pings.ts b/apps/api/src/routes/pings.ts index bc1f21f..3d2fbf4 100644 --- a/apps/api/src/routes/pings.ts +++ b/apps/api/src/routes/pings.ts @@ -65,13 +65,15 @@ export const ingest = new Elysia() const meta = body.meta ? { ...body.meta } : {}; if (body.cert_expiry_days != null) meta.cert_expiry_days = body.cert_expiry_days; + const checkedAt = body.checked_at ? new Date(body.checked_at) : null; const scheduledAt = body.scheduled_at ? new Date(body.scheduled_at) : null; const jitterMs = body.jitter_ms ?? null; const [ping] = await sql` - INSERT INTO pings (monitor_id, scheduled_at, jitter_ms, status_code, latency_ms, up, error, meta, region, run_id) + INSERT INTO pings (monitor_id, checked_at, scheduled_at, jitter_ms, status_code, latency_ms, up, error, meta, region, run_id) VALUES ( ${body.monitor_id}, + ${checkedAt ?? sql`now()`}, ${scheduledAt}, ${jitterMs}, ${body.status_code ?? null}, @@ -93,6 +95,7 @@ export const ingest = new Elysia() }, { body: t.Object({ monitor_id: t.String(), + checked_at: t.Optional(t.Nullable(t.String())), scheduled_at: t.Optional(t.Nullable(t.String())), jitter_ms: t.Optional(t.Nullable(t.Number())), status_code: t.Optional(t.Nullable(t.Number())), diff --git a/apps/monitor/src/runner.rs b/apps/monitor/src/runner.rs index 304ffb2..1bd1ada 100644 --- a/apps/monitor/src/runner.rs +++ b/apps/monitor/src/runner.rs @@ -100,6 +100,7 @@ pub async fn fetch_and_run( Ok(r) => r, Err(_) => PingResult { monitor_id: monitor.id.clone(), + checked_at: Some(chrono::Utc::now().to_rfc3339()), scheduled_at: scheduled_at_iso.clone(), jitter_ms: None, status_code: None, @@ -125,6 +126,9 @@ pub async fn fetch_and_run( } async fn run_check(client: &reqwest::Client, monitor: &Monitor, scheduled_at: Option, region: &str, run_id: &str) -> PingResult { + // Record when the check actually started (used as checked_at in the ping) + let checked_at = chrono::Utc::now().to_rfc3339(); + // Compute jitter: how late we actually started vs when we were scheduled let jitter_ms: Option = scheduled_at.as_deref().and_then(|s| { let scheduled = chrono::DateTime::parse_from_rfc3339(s).ok()?; @@ -175,6 +179,7 @@ async fn run_check(client: &reqwest::Client, monitor: &Monitor, scheduled_at: Op debug!("{} check error: {e}", monitor.url); PingResult { monitor_id: monitor.id.clone(), + checked_at: Some(checked_at.clone()), scheduled_at, jitter_ms, status_code: None, @@ -236,6 +241,7 @@ async fn run_check(client: &reqwest::Client, monitor: &Monitor, scheduled_at: Op PingResult { monitor_id: monitor.id.clone(), + checked_at: Some(checked_at), scheduled_at, jitter_ms, status_code: Some(status), diff --git a/apps/monitor/src/types.rs b/apps/monitor/src/types.rs index 36067e3..c59b244 100644 --- a/apps/monitor/src/types.rs +++ b/apps/monitor/src/types.rs @@ -33,6 +33,7 @@ pub struct Monitor { #[derive(Debug, Serialize)] pub struct PingResult { pub monitor_id: String, + pub checked_at: Option, pub scheduled_at: Option, pub jitter_ms: Option, pub status_code: Option,