fix(02-11): gate three leaked background pollers to activate/deactivate
Demo images / Build & push demo images (push) Has been cancelled
Demo images / Build & push demo images (push) Has been cancelled
Fleet.vue's useFleetData() (60s telemetry.fleet-status/-alerts poll), Server.vue's FipsNetworkCard.vue (15s fips.status poll), and Web5.vue's Web5Monitoring.vue (30s system.stats poll — redundant with Home.vue's own correctly-gated 10s poll of the same store) all armed their setInterval in onMounted and only disarmed it in onUnmounted/ onBeforeUnmount. That was harmless before 02-04 registered their owning views in KEEP_ALIVE_PATHS (the view was destroyed on every tab-away, so the teardown hook fired every time); once KeepAlive keeps the instance alive, the teardown hook never fires again and the poll ran forever in the background regardless of which dashboard tab was showing. Gated arm/disarm to onActivated/onDeactivated, mirroring Server.vue's own vpnPollInterval fix from 02-04 exactly. Added regression tests to keepAliveLifecycle.test.ts mounting each real component under a synthetic KeepAlive with fake timers; confirmed RED against the pre-fix code (git stash) before confirming GREEN with the fix restored. Full suite (95 files/788 tests), type-check and build all green. keepAliveTabs.test.ts is byte-for-byte unmodified. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e5c38866ca
commit
2c25e512a7
@@ -119,7 +119,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, onActivated, onDeactivated, ref } from 'vue'
|
||||
import { rpcClient } from '@/api/rpc-client'
|
||||
import { useCachedResource } from '@/composables/useCachedResource'
|
||||
import { safeClipboardWrite } from '@/views/web5/utils'
|
||||
@@ -262,14 +262,42 @@ async function reconnectAnchor() {
|
||||
|
||||
// Poll instead of one-shot: a long-lived page (the kiosk especially) was
|
||||
// stuck showing whatever anchor state existed at mount time forever.
|
||||
//
|
||||
// 02-11 gap closure: this card is rendered inside Server.vue, which joined
|
||||
// KEEP_ALIVE_PATHS in 02-04 — but this poll was only ever armed in
|
||||
// onMounted and disarmed in onUnmounted, so once Server.vue (and this card
|
||||
// with it) is KeepAlive'd, onUnmounted never fires again and the poll ran
|
||||
// forever in the background, firing `fips.status` every 15s regardless of
|
||||
// which dashboard tab was actually showing (`document.hidden` only helps
|
||||
// for a backgrounded BROWSER tab, not an in-SPA tab switch). Arm/disarm now
|
||||
// follows activate/deactivate, mirroring Server.vue's own vpnPollInterval
|
||||
// fix from 02-04; calling armFipsPoll from both onMounted and onActivated
|
||||
// on a fresh KeepAlive-wrapped mount is safe since it always clears any
|
||||
// prior timer first.
|
||||
let statusInterval: ReturnType<typeof setInterval> | null = null
|
||||
onMounted(() => {
|
||||
function armFipsPoll() {
|
||||
if (statusInterval) clearInterval(statusInterval)
|
||||
statusInterval = setInterval(() => {
|
||||
if (document.hidden) return
|
||||
void statusRes.refresh()
|
||||
}, 15000)
|
||||
}
|
||||
function disarmFipsPoll() {
|
||||
if (statusInterval) {
|
||||
clearInterval(statusInterval)
|
||||
statusInterval = null
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
armFipsPoll()
|
||||
})
|
||||
onActivated(() => {
|
||||
armFipsPoll()
|
||||
})
|
||||
onDeactivated(() => {
|
||||
disarmFipsPoll()
|
||||
})
|
||||
onUnmounted(() => {
|
||||
if (statusInterval) clearInterval(statusInterval)
|
||||
disarmFipsPoll()
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user