fix(ui): single-flight scan poll so status line does not alternate

Made-with: Cursor
This commit is contained in:
PTah
2026-04-13 13:45:54 +10:00
parent 42e3c0c925
commit 0de279926f
+18
View File
@@ -249,6 +249,8 @@
/** @type {{if_index:number,bridge_port:number,mac:string,learned_ip:string}[]} */
let lastPortDevItems = [];
let selectedFdbKey = null;
/** Увеличивается при каждом новом pollScanUntilDone — снимает гонку createScan vs watchScan (чередование строк статуса). */
let scanPollSeq = 0;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -287,31 +289,47 @@
* @param {{ intervalMs?: number, maxWaitMs?: number, onDone?: function }} opts
*/
async function pollScanUntilDone(scanId, opts = {}) {
const mySeq = ++scanPollSeq;
const intervalMs = opts.intervalMs ?? 1000;
const maxWaitMs = opts.maxWaitMs ?? 20 * 60 * 1000;
const started = Date.now();
while (Date.now() - started < maxWaitMs) {
if (mySeq !== scanPollSeq) {
return null;
}
let job;
try {
job = await fetchScanJob(scanId);
} catch (e) {
if (mySeq === scanPollSeq) {
setStatus(`Ошибка опроса скана: ${e.message}`);
}
return null;
}
if (mySeq !== scanPollSeq) {
return null;
}
setStatus(describeScanProgress(job));
if (job.status === "done" || job.status === "failed" || job.status === "canceled") {
if (mySeq !== scanPollSeq) {
return null;
}
if (opts.onDone) {
try {
await opts.onDone(job);
} catch (e) {
if (mySeq === scanPollSeq) {
setStatus((statusEl.textContent || "") + ` | Ошибка в onDone: ${e.message}`);
}
}
}
return job;
}
await sleep(intervalMs);
}
if (mySeq === scanPollSeq) {
setStatus(`Таймаут ожидания скана ${scanId} (${Math.round(maxWaitMs / 60000)} мин).`);
}
return null;
}