Correct bucket latency telemetry (PR 1282, 398598e)
- Render bucket latency rows inside #bucket-latency-rows (never replace panel); preserve heading + aria-labelledby; role=list/listitem rows - Remove fabricated 1ms floor: sub-ms yields 0, UI shows '<1 ms' - Strict latency types: reject null/bool/str/float/negative/Infinity/huge (frontend + backend); no coercion or clipping - Failed upstream-attempt duration never overwrites prior successful latency; stale-but-measured feeds labeled 'last known' truthfully - Notifications fetch starts immediately (auth-independent), concurrent with shared current_user auth; deterministic concurrency proof - Repair tests: real DOM transitions (browser-verified), production failure shape, panel-hidden assertion, malformed-value matrix
This commit is contained in:
1 parent
398598e154
commit
81d288405f
4 files changed
+512
-160
No files matched your search
@@ -15,8 +15,14 @@
|
||||
}
|
||||
|
||||
function boundedLatencyMs(value) {
|
||||
const ms = Number(value);
|
||||
return Number.isFinite(ms) && ms >= 0 ? Math.min(Math.round(ms), 3600000) : null;
|
||||
// Strict acceptance only: actual finite nonnegative bounded integers.
|
||||
// Rejects null, booleans, strings, arrays, floats, fractions, negatives,
|
||||
// Infinity, and huge values. No Number() coercion, no clipping.
|
||||
if (typeof value !== 'number') return null;
|
||||
if (!Number.isFinite(value)) return null;
|
||||
if (!Number.isInteger(value)) return null;
|
||||
if (value < 0 || value > 3600000) return null;
|
||||
return value;
|
||||
}
|
||||
|
||||
const latencyBuckets = [
|
||||
@@ -67,12 +73,24 @@
|
||||
|
||||
function formatLatency(ms) {
|
||||
if (ms === null) return 'not measured';
|
||||
if (ms === 0) return '<1 ms';
|
||||
if (ms >= 10000) return Math.round(ms / 1000) + ' s';
|
||||
if (ms >= 1000) return (ms / 1000).toFixed(1) + ' s';
|
||||
return ms + ' ms';
|
||||
}
|
||||
|
||||
function renderBucketLatency(description, panel) {
|
||||
// Render rows *inside* the existing #bucket-latency-rows container so the
|
||||
// panel heading and its aria-labelledby target are never replaced. Each
|
||||
// generated row carries role=listitem so the list semantics hold.
|
||||
const rowsContainer = (typeof panel.querySelector === 'function')
|
||||
? (panel.querySelector('#bucket-latency-rows') || panel)
|
||||
: panel;
|
||||
if (rowsContainer !== panel) {
|
||||
rowsContainer.innerHTML = '';
|
||||
} else {
|
||||
panel.innerHTML = '';
|
||||
}
|
||||
const rows = description.feeds.map(feed => ({
|
||||
key: feed.key,
|
||||
label: feed.label,
|
||||
@@ -81,20 +99,26 @@
|
||||
}));
|
||||
if (!rows.some(row => row.latencyMs !== null)) {
|
||||
panel.hidden = true;
|
||||
panel.innerHTML = '';
|
||||
return rows;
|
||||
}
|
||||
panel.hidden = false;
|
||||
panel.innerHTML = rows.map(row => {
|
||||
for (const row of rows) {
|
||||
const slow = row.latencyMs !== null && row.latencyMs >= 2000 ? ' slow' : '';
|
||||
const value = formatLatency(row.latencyMs);
|
||||
// A delayed feed shows the last measurement that succeeded, so say so.
|
||||
const suffix = row.stale && row.latencyMs !== null ? ' <span class="small muted">last known</span>' : '';
|
||||
return '<div class="bucket-latency-row" data-bucket="' + row.key + '">' +
|
||||
'<strong>' + row.label + '</strong>' +
|
||||
'<span class="bucket-latency-value' + slow + '">' + value + suffix + '</span>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
// A stale feed shows the last measurement that succeeded, so say so.
|
||||
const suffix = row.stale && row.latencyMs !== null
|
||||
? ' <span class="small muted">last known</span>' : '';
|
||||
const html = '<div class="bucket-latency-row' + slow + '" role="listitem" data-bucket="' +
|
||||
row.key + '"><strong>' + row.label + '</strong>' +
|
||||
'<span class="bucket-latency-value' + slow + '">' + value + suffix + '</span></div>';
|
||||
if (typeof document !== 'undefined') {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = html;
|
||||
rowsContainer.appendChild(wrapper.firstChild);
|
||||
} else {
|
||||
rowsContainer.appendChild({outerHTML: html});
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user