v3.28.7: the batch panel freeze
ramBatchFetch's re-entrancy guard (_ramBatchFetching) is only cleared when the fetch settles, and ramBatchApplyStatus returned without rendering whenever it decided a fetch was due - so one stalled /api/ram-batch/status request (the browser's fetch has no timeout) froze the whole panel (counts, phase, notice, throbber) at the last successful render while the server kept installing (live 2026-10-14: 31 installs, the panel stuck at "Installed: 12"; the log showed all 31 attempts and a healthy /api/status cadence, so the data was there). - The summary render now runs on every poll before the fetch decision: the headline (phase, current card, counts, notice) always follows the 2 s /api/status poll; the detailed fetch only adds the attempts table. - A fetch guard older than RAM_BATCH_FETCH_STALE_MS (10 s) is released, so a stalled fetch cannot block the report forever - the next poll retries and the attempts table recovers. Reproduced with the page's real functions: 12 good fetches, the 13th hung -> the panel stuck at 12 (the reported number); with the fix it follows the summary to 31 and the stale guard retries. Tests: a hung fetch keeps the counts following the summary; a stale guard is released and retried (a fresh one is kept). 919 frontend + 928 Python; sw cache simple-v445.
This commit is contained in:
+15
-3
@@ -1910,7 +1910,7 @@
|
||||
// ===== Version =====
|
||||
// Single source of truth for the PWA version: shown in the header and used
|
||||
// by the server version check in pysimConnect().
|
||||
const SIMPLE_VERSION = '3.28.6';
|
||||
const SIMPLE_VERSION = '3.28.7';
|
||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||
|
||||
// ===== view history (the browser Back/Forward buttons) =====
|
||||
@@ -10155,8 +10155,11 @@ function ramHideProgress() {
|
||||
// (the attempts list) is fetched only when the summary says it changed.
|
||||
let _ramBatchLast = null; // the last detailed /api/ram-batch/status
|
||||
let _ramBatchFetching = false;
|
||||
let _ramBatchFetchAt = 0; // when the in-flight fetch started (the watchdog)
|
||||
let _ramBatchSummary = null; // /api/status.ram_batch
|
||||
let _ramBatchProgress = null; // /api/status.ram_progress
|
||||
// A fetch that never settled must not block the report forever (v3.28.7).
|
||||
const RAM_BATCH_FETCH_STALE_MS = 10000;
|
||||
|
||||
function ramBatchPanelVisible() {
|
||||
const op = document.getElementById('ram-op');
|
||||
@@ -10167,6 +10170,7 @@ function ramBatchPanelVisible() {
|
||||
async function ramBatchFetch() {
|
||||
if (_ramBatchFetching) return;
|
||||
_ramBatchFetching = true;
|
||||
_ramBatchFetchAt = Date.now();
|
||||
try {
|
||||
_ramBatchLast = await pysimFetch('/api/ram-batch/status');
|
||||
} catch (e) { /* the next poll retries */ }
|
||||
@@ -10181,14 +10185,22 @@ function ramBatchApplyStatus(status) {
|
||||
_ramBatchSummary = status.ram_batch || null;
|
||||
_ramBatchProgress = status.ram_progress || null;
|
||||
if (!ramBatchPanelVisible()) return;
|
||||
// The summary carries the headline (the phase, the current card, the
|
||||
// counts, the notice): render it on every poll, even when a detailed fetch
|
||||
// is due or stuck - a hung fetch used to freeze the whole panel at the
|
||||
// last successful render (v3.28.7).
|
||||
ramBatchRender();
|
||||
if (_ramBatchFetching && Date.now() - _ramBatchFetchAt > RAM_BATCH_FETCH_STALE_MS) {
|
||||
// the in-flight fetch is stale (a stalled connection): release the
|
||||
// guard so this poll retries and the report can recover
|
||||
_ramBatchFetching = false;
|
||||
}
|
||||
const total = _ramBatchSummary ? (_ramBatchSummary.attempts_total || 0) : 0;
|
||||
const active = _ramBatchSummary ? !!_ramBatchSummary.active : false;
|
||||
if (!_ramBatchLast || (_ramBatchLast.attempts_total || 0) !== total
|
||||
|| !!_ramBatchLast.active !== active) {
|
||||
ramBatchFetch();
|
||||
return;
|
||||
}
|
||||
ramBatchRender();
|
||||
}
|
||||
|
||||
function ramBatchRender() {
|
||||
|
||||
Reference in New Issue
Block a user