fix(update): concurrent apply reads as progress, not failure; idle-IO extraction
Demo images / Build & push demo images (push) Successful in 5m18s

"Another update operation is already running" surfaced as a scary
failure while the update was in fact applying fine (OptiPlex, v1.7.118
rollout). The apply path now joins the in-flight install — same
overlay, same wait-for-new-version polling — and a concurrent download
attempt shows a calm in-progress note (EN+ES strings added). The
backend's tarball extractions run under ionice -c3 nice -n10 so a
200MB update can't starve podman/status calls into multi-minute
timeouts on small disks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-07-29 10:38:11 -04:00
co-authored by Claude Fable 5
parent 00f1892bf8
commit 49ec294dea
5 changed files with 48 additions and 8 deletions
+19
View File
@@ -978,6 +978,11 @@ async function downloadUpdate() {
updateInProgress.value = false
await loadStatus()
showStatus(t('systemUpdate.upToDateMessage'))
} else if (/already running/i.test(msg)) {
// A download/apply is already in flight (auto-updater or another tab) —
// that's progress, not failure. Re-sync state and say so calmly.
await loadStatus()
showStatus(t('systemUpdate.downloadInProgress'))
} else {
// A failed download is NOT a staged update — return the UI to the
// Download button so the user can retry, instead of stranding them on
@@ -1065,6 +1070,20 @@ async function applyUpdate() {
setTimeout(() => window.location.reload(), 3000)
}
} catch (e) {
// "Another update operation is already running" is NOT a failure — an
// apply (or the auto-updater) is already doing the work. Presenting it
// as an error made a successfully-updating node look broken (OptiPlex,
// v1.7.118 rollout). Join the in-flight apply instead: same overlay,
// same wait-for-new-version polling.
if (/already running/i.test(errorMessage(e))) {
applying.value = false
if (target) {
startInstallOverlay(target)
} else {
showStatus(t('systemUpdate.applyInProgress'))
}
return
}
showStatus(t('systemUpdate.applyFailed'), true)
if (import.meta.env.DEV) console.warn('Apply failed', e)
applying.value = false