[Perl] DAQ system for the FAPG.
perf abort obsolete chart requests
- attach abort signals to chart and recent-reading fetches - cancel active probe requests when graph controls change range
Changed files
roles/dashboard/public/js/dashboard.js
@@ -12,7 +12,7 @@
12
12
button.addEventListener("click", () => probes.activateTab(button.dataset.probe));
13
13
});
14
14
15
Removed:
initialiseGraphControls(timeframe, probes.loadDisplayed);
15
Added:
initialiseGraphControls(timeframe, probes.reloadDisplayed);
16
16
17
17
window.addEventListener("hashchange", () => {
18
18
const probe = probes.probeFromLocation();
roles/dashboard/public/js/dashboard/api.js
@@ -1,5 +1,5 @@
1
Removed:
async function fetchJson(url) {
2
Removed:
const response = await fetch(url);
1
Added:
async function fetchJson(url, options = {}) {
2
Added:
const response = await fetch(url, options);
3
3
4
4
if (!response.ok) {
5
5
throw new Error(`HTTP ${response.status}`);
@@ -21,18 +21,19 @@
21
21
return readings.length ? readings[readings.length - 1] : null;
22
22
}
23
23
24
Removed:
export async function fetchProbeData(probe, timeframe, range, includeReadings = false) {
24
Added:
export async function fetchProbeData(probe, timeframe, range, includeReadings = false, signal = null) {
25
25
const seriesParams = new URLSearchParams({
26
26
timeframe,
27
27
range: String(range),
28
28
smooth: "1"
29
29
});
30
30
const readingsParams = new URLSearchParams({ limit: "10" });
31
Added:
const options = signal ? { signal } : {};
31
32
const readingsRequest = includeReadings
32
Removed:
? fetchJson(`/api/readings/${probe}?${readingsParams}`)
33
Added:
? fetchJson(`/api/readings/${probe}?${readingsParams}`, options)
33
34
: Promise.resolve({ readings: [] });
34
35
const [series, readings] = await Promise.all([
35
Removed:
fetchJson(`/api/readings/${probe}/series?${seriesParams}`),
36
Added:
fetchJson(`/api/readings/${probe}/series?${seriesParams}`, options),
36
37
readingsRequest
37
38
]);
38
39
roles/dashboard/public/js/dashboard/charts.js
@@ -212,7 +212,7 @@
212
212
const charts = new Map();
213
213
const loading = new Map();
214
214
215
Removed:
async function requestProbe(probe) {
215
Added:
async function requestProbe(probe, signal) {
216
216
const canvas = chartElement(probe);
217
217
if (!probe || !canvas) return;
218
218
@@ -224,7 +224,8 @@
224
224
probe,
225
225
timeframe.selected(),
226
226
timeframe.range(),
227
Removed:
hasMessageTable
227
Added:
hasMessageTable,
228
Added:
signal
228
229
);
229
230
const series = chartSeries(data.series, timeframe.selected());
230
231
const latest = [...data.readings]
@@ -264,21 +265,30 @@
264
265
}
265
266
renderMessageTable(probe, data.readings);
266
267
} catch (error) {
268
Added:
if (error.name === "AbortError") return;
269
Added:
267
270
if (status) status.textContent = `Could not load ${probe} readings: ${error.message}`;
268
271
renderMessageTable(probe, []);
269
272
}
270
273
}
271
274
272
Removed:
function loadProbe(probe) {
273
Removed:
if (loading.has(probe)) return loading.get(probe);
275
Added:
function loadProbe(probe, { replace = false } = {}) {
276
Added:
const active = loading.get(probe);
277
Added:
if (active && !replace) return active.request;
278
Added:
if (active) active.controller.abort();
274
279
275
Removed:
const request = requestProbe(probe).finally(() => {
276
Removed:
if (loading.get(probe) === request) loading.delete(probe);
280
Added:
const entry = { controller: new AbortController(), request: null };
281
Added:
entry.request = requestProbe(probe, entry.controller.signal).finally(() => {
282
Added:
if (loading.get(probe) === entry) loading.delete(probe);
277
283
});
278
Removed:
loading.set(probe, request);
279
Removed:
return request;
284
Added:
loading.set(probe, entry);
285
Added:
return entry.request;
280
286
}
281
287
288
Added:
function loadDisplayed(options = {}) {
289
Added:
return Promise.all(displayedProbes().map(probe => loadProbe(probe, options)));
290
Added:
}
291
Added:
282
292
function activateTab(probe) {
283
293
document.querySelectorAll(".tab-button").forEach(button => {
284
294
const active = button.dataset.probe === probe;
@@ -309,7 +319,8 @@
309
319
activateTab,
310
320
displayedProbes,
311
321
loadProbe,
312
Removed:
loadDisplayed: () => Promise.all(displayedProbes().map(loadProbe)),
322
Added:
loadDisplayed,
323
Added:
reloadDisplayed: () => loadDisplayed({ replace: true }),
313
324
probeFromLocation,
314
325
probeFromHash: () => window.location.hash.match(/^#probe-([a-z]+)$/)?.[1] || null
315
326
};