From 7b98ae78e521d901e4dae94aaac2dab6d303e542 Mon Sep 17 00:00:00 2001 From: M1 Date: Wed, 18 Mar 2026 17:03:17 +0400 Subject: [PATCH] =?UTF-8?q?fix:=20run=5Fid=20=3D=20hash(monitor=5Fid,=20in?= =?UTF-8?q?terval=5Fbucket)=20=E2=80=94=20unique=20per=20window,=20consist?= =?UTF-8?q?ent=20across=20regions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/monitor/src/runner.rs | 10 ++++++++-- apps/web/src/views/detail.ejs | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/monitor/src/runner.rs b/apps/monitor/src/runner.rs index 8cdd72e..7b71837 100644 --- a/apps/monitor/src/runner.rs +++ b/apps/monitor/src/runner.rs @@ -53,14 +53,20 @@ pub async fn fetch_and_run( let coordinator_url = coordinator_url.to_string(); let token = token.to_string(); let region_owned = region.to_string(); - // Derive run_id from the monitor's scheduled_at bucket + // Derive run_id by hashing (monitor_id, interval_bucket) so every region + // checking within the same scheduled window gets the same short ID. let run_id_owned = { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; let epoch = monitor.scheduled_at.as_deref() .and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok()) .map(|dt| dt.timestamp()) .unwrap_or_else(|| chrono::Utc::now().timestamp()); let bucket = epoch / monitor.interval_s; - format!("{}:{}", &monitor.id[..8.min(monitor.id.len())], bucket) + let mut h = DefaultHasher::new(); + monitor.id.hash(&mut h); + bucket.hash(&mut h); + format!("{:016x}", h.finish()) }; let in_flight = in_flight.clone(); tokio::spawn(async move { diff --git a/apps/web/src/views/detail.ejs b/apps/web/src/views/detail.ejs index d56f9b2..dc9e6ac 100644 --- a/apps/web/src/views/detail.ejs +++ b/apps/web/src/views/detail.ejs @@ -107,7 +107,7 @@ <%= c.status_code != null ? c.status_code : '—' %> <%= c.latency_ms != null ? c.latency_ms + 'ms' : '—' %> <%= c.region ? (regionFlag[c.region] || '🌐') + ' ' + c.region : '—' %> - <%= c.run_id ? c.run_id.slice(0, 8) : '—' %> + <%= c.run_id ? c.run_id.slice(0, 8) + '…' : '—' %> <%~ it.timeAgoSSR(c.checked_at) %><% if (c.jitter_ms != null) { %> (+<%= c.jitter_ms %>ms)<% } %> <%= c.error ? c.error : '' %> @@ -344,7 +344,7 @@ ${ping.status_code ?? '—'} ${ping.latency_ms != null ? ping.latency_ms + 'ms' : '—'} ${regionDisplay} - ${ping.run_id ? ping.run_id.slice(0, 8) : '—'} + ${ping.run_id ? ping.run_id.slice(0, 8) + '…' : '—'} ${timeAgo(ping.checked_at)}${ping.jitter_ms != null ? ` (+${ping.jitter_ms}ms)` : ''} ${ping.error ? escapeHtml(ping.error) : ''} `;