fix: a refresh asked for while another runs is no longer dropped (closes #581)
check / check (push) Waiting to run
e2e / e2e-chrome (push) Waiting to run
e2e / e2e-firefox (push) Waiting to run

doRefreshAndRender() returned at once when a refresh was already running. An import asks for a refresh after its address scan, and that request was dropped when it came during a refresh, so the addresses the scan found showed 0.0000 until the next ten-second refresh. A request made through ctx while a refresh runs now leads to one more refresh once the running one ends, however many such requests came in. A tick of the ten-second timer during a refresh is still dropped, so the wallet asks the node no more often than before.

Model: opus-5-5
This commit was merged in pull request #702.
This commit is contained in:
2026-10-27 20:14:09 +01:00
parent 08e47c39ad
commit 8998d6c661
2 changed files with 184 additions and 10 deletions
+27 -10
View File
@@ -65,7 +65,14 @@ function renderWalletList() {
const pageClosed = new AbortController();
window.addEventListener("pagehide", () => pageClosed.abort());
// While a refresh runs, a request through ctx is not dropped. The request sets
// refreshAgain, and one more refresh runs once the running one ends. Several
// requests in that time lead to one more refresh, not several. An import asks
// for a refresh after its address scan. A refresh already running does not
// have the addresses the scan found
// (https://git.eeqj.de/sneak/AutistMask/issues/581).
let refreshInFlight = false;
let refreshAgain = false;
// The ten-second refresh startRefresh() starts, stopped when the popup moves to
// the recovery screen: there is no profile left to refresh.
@@ -89,7 +96,10 @@ let refreshTimer = null;
// user turned "Use Blockscout" off. So the save drops every token the user has
// not tracked if the stored setting is off by then.
async function doRefreshAndRender() {
if (refreshInFlight) return;
if (refreshInFlight) {
refreshAgain = true;
return;
}
refreshInFlight = true;
try {
await followStoredSettings();
@@ -132,28 +142,35 @@ async function doRefreshAndRender() {
});
renderWalletList();
} catch (e) {
// Every call site fires this and walks away — the boot below, the ten
// second interval, and eight views through ctx — so it must never
// reject: an unhandled rejection is not a report of anything. The save
// inside it reports its own failure through onSaveFailure() (see
// src/shared/state.js); what is left here is a failed network round
// trip, which the next tick retries.
// No caller waits for this function, so it must never reject. An
// unhandled rejection reports nothing. The save inside it reports its
// own failure through onSaveFailure() (see src/shared/state.js); what
// is left here is a failed network round trip, which the next tick
// retries.
log.errorf("popup: background refresh failed:", e);
} finally {
refreshInFlight = false;
}
if (refreshAgain) {
refreshAgain = false;
doRefreshAndRender();
}
}
// Refreshes now and every ten seconds from then on. Called once a wallet
// exists: by init() when the popup opens with one, and by AddWallet when it
// adds one, which in a popup that opened on Welcome is the first
// (https://git.eeqj.de/sneak/AutistMask/issues/530). With the refresh already
// running it starts no second one, and on the recovery screen it does nothing.
// (https://git.eeqj.de/sneak/AutistMask/issues/530). With the ten-second
// refresh already started, it starts no second one. On the recovery screen it
// does nothing.
function startRefresh() {
if (!$("view-state-recovery").classList.contains("hidden")) return;
doRefreshAndRender();
if (refreshTimer === null) {
refreshTimer = setInterval(doRefreshAndRender, 10000);
// A tick that finds a refresh running is dropped.
refreshTimer = setInterval(() => {
if (!refreshInFlight) return doRefreshAndRender();
}, 10000);
}
}