fix: harden container status polling after idle

This commit is contained in:
JOJO 2025-12-16 20:32:24 +08:00
parent 7f7a7e9f94
commit 599f331c35

View File

@ -76,6 +76,9 @@ export const useResourceStore = defineStore('resource', {
up_bps: null up_bps: null
} as ContainerNetRate, } as ContainerNetRate,
lastContainerSample: null as ContainerSample | null, lastContainerSample: null as ContainerSample | null,
containerStatsInFlight: false,
containerStatsFailCount: 0,
containerStatsIntervalMs: 500,
containerStatsTimer: null as ReturnType<typeof setInterval> | null, containerStatsTimer: null as ReturnType<typeof setInterval> | null,
projectStorageTimer: null as ReturnType<typeof setInterval> | null, projectStorageTimer: null as ReturnType<typeof setInterval> | null,
projectStorageInFlight: false, projectStorageInFlight: false,
@ -202,33 +205,71 @@ export const useResourceStore = defineStore('resource', {
this.containerStatus = status; this.containerStatus = status;
}, },
async pollContainerStats() { async pollContainerStats() {
if (typeof document !== 'undefined' && document.hidden) {
return;
}
if (this.containerStatsInFlight) {
return;
}
this.containerStatsInFlight = true;
const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
const timeoutId = controller ? window.setTimeout(() => controller.abort(), 4000) : null;
try { try {
const response = await fetch('/api/container-status'); const response = await fetch('/api/container-status', {
signal: controller?.signal
});
if (!response.ok) { if (!response.ok) {
return; throw new Error(`http-${response.status}`);
} }
const data = await response.json(); const data = await response.json();
if (data.success) { if (data.success) {
this.updateContainerStatus(data.data || null); this.updateContainerStatus(data.data || null);
} }
this.containerStatsFailCount = 0;
if (this.containerStatsIntervalMs > 500) {
this._restartContainerStatsTimer(500);
}
} catch (error) { } catch (error) {
console.warn('获取容器状态异常:', error); console.warn('获取容器状态异常:', error);
this.containerStatsFailCount += 1;
if (this.containerStatsFailCount >= 3) {
const nextInterval = Math.min(this.containerStatsIntervalMs * 2, 10_000);
this._restartContainerStatsTimer(nextInterval);
}
} finally {
this.containerStatsInFlight = false;
if (timeoutId) {
clearTimeout(timeoutId);
}
} }
}, },
startContainerStatsPolling() { startContainerStatsPolling() {
if (this.containerStatsTimer) { if (this.containerStatsTimer) {
return; return;
} }
this.containerStatsFailCount = 0;
this.containerStatsIntervalMs = 500;
this.pollContainerStats(); this.pollContainerStats();
this.containerStatsTimer = setInterval(() => { this.containerStatsTimer = setInterval(() => {
this.pollContainerStats(); this.pollContainerStats();
}, 500); }, this.containerStatsIntervalMs);
}, },
stopContainerStatsPolling() { stopContainerStatsPolling() {
if (this.containerStatsTimer) { if (this.containerStatsTimer) {
clearInterval(this.containerStatsTimer); clearInterval(this.containerStatsTimer);
this.containerStatsTimer = null; this.containerStatsTimer = null;
} }
this.containerStatsInFlight = false;
},
_restartContainerStatsTimer(interval: number) {
if (this.containerStatsTimer) {
clearInterval(this.containerStatsTimer);
this.containerStatsTimer = null;
}
this.containerStatsIntervalMs = interval;
this.containerStatsTimer = setInterval(() => {
this.pollContainerStats();
}, this.containerStatsIntervalMs);
}, },
async pollProjectStorage() { async pollProjectStorage() {
if (this.projectStorageInFlight) { if (this.projectStorageInFlight) {