fix: 缓存项目存储轮询并降低频率
This commit is contained in:
parent
fc88a22272
commit
e27bc62ca7
@ -52,6 +52,9 @@ const buildDefaultQuota = (): UsageQuota => ({
|
||||
role: 'user'
|
||||
});
|
||||
|
||||
const PROJECT_STORAGE_POLL_INTERVAL_MS = 60_000;
|
||||
const PROJECT_STORAGE_POLL_INTERVAL_MAX_MS = 300_000;
|
||||
|
||||
export const useResourceStore = defineStore('resource', {
|
||||
state: () => ({
|
||||
tokenPanelCollapsed: true,
|
||||
@ -75,6 +78,9 @@ export const useResourceStore = defineStore('resource', {
|
||||
lastContainerSample: null as ContainerSample | null,
|
||||
containerStatsTimer: null as ReturnType<typeof setInterval> | null,
|
||||
projectStorageTimer: null as ReturnType<typeof setInterval> | null,
|
||||
projectStorageInFlight: false,
|
||||
projectStorageFailCount: 0,
|
||||
projectStorageIntervalMs: PROJECT_STORAGE_POLL_INTERVAL_MS,
|
||||
usageQuota: buildDefaultQuota(),
|
||||
usageQuotaTimer: null as ReturnType<typeof setInterval> | null
|
||||
}),
|
||||
@ -225,6 +231,10 @@ export const useResourceStore = defineStore('resource', {
|
||||
}
|
||||
},
|
||||
async pollProjectStorage() {
|
||||
if (this.projectStorageInFlight) {
|
||||
return;
|
||||
}
|
||||
this.projectStorageInFlight = true;
|
||||
try {
|
||||
const resp = await fetch('/api/project-storage');
|
||||
if (!resp.ok) {
|
||||
@ -236,9 +246,26 @@ export const useResourceStore = defineStore('resource', {
|
||||
this.projectStorage.limit_bytes = data.data.limit_bytes ?? null;
|
||||
this.projectStorage.limit_label = data.data.limit_label || '';
|
||||
this.projectStorage.usage_percent = data.data.usage_percent ?? null;
|
||||
this.projectStorageFailCount = 0;
|
||||
if (this.projectStorageIntervalMs > PROJECT_STORAGE_POLL_INTERVAL_MS) {
|
||||
this._restartProjectStorageTimer(PROJECT_STORAGE_POLL_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
this.projectStorageFailCount += 1;
|
||||
console.warn('获取存储信息失败:', err);
|
||||
if (this.projectStorageFailCount >= 3) {
|
||||
const slower = Math.min(
|
||||
this.projectStorageIntervalMs * 2,
|
||||
PROJECT_STORAGE_POLL_INTERVAL_MAX_MS
|
||||
);
|
||||
if (slower !== this.projectStorageIntervalMs) {
|
||||
console.warn(`连续获取失败,存储轮询间隔调整为 ${Math.round(slower / 1000)} 秒`);
|
||||
this._restartProjectStorageTimer(slower);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
this.projectStorageInFlight = false;
|
||||
}
|
||||
},
|
||||
startProjectStoragePolling() {
|
||||
@ -248,13 +275,25 @@ export const useResourceStore = defineStore('resource', {
|
||||
this.pollProjectStorage();
|
||||
this.projectStorageTimer = setInterval(() => {
|
||||
this.pollProjectStorage();
|
||||
}, 5000);
|
||||
}, this.projectStorageIntervalMs);
|
||||
},
|
||||
stopProjectStoragePolling() {
|
||||
if (this.projectStorageTimer) {
|
||||
clearInterval(this.projectStorageTimer);
|
||||
this.projectStorageTimer = null;
|
||||
}
|
||||
this.projectStorageInFlight = false;
|
||||
this.projectStorageFailCount = 0;
|
||||
this.projectStorageIntervalMs = PROJECT_STORAGE_POLL_INTERVAL_MS;
|
||||
},
|
||||
_restartProjectStorageTimer(intervalMs: number) {
|
||||
if (this.projectStorageTimer) {
|
||||
clearInterval(this.projectStorageTimer);
|
||||
}
|
||||
this.projectStorageIntervalMs = Math.max(intervalMs, 10_000);
|
||||
this.projectStorageTimer = setInterval(() => {
|
||||
this.pollProjectStorage();
|
||||
}, this.projectStorageIntervalMs);
|
||||
},
|
||||
normalizeUsageQuota(raw: any) {
|
||||
const base = buildDefaultQuota();
|
||||
|
||||
@ -172,6 +172,8 @@ CSRF_EXEMPT_PATHS = {"/api/csrf-token"}
|
||||
FAILED_LOGIN_LIMIT = 5
|
||||
FAILED_LOGIN_LOCK_SECONDS = 300
|
||||
SOCKET_TOKEN_TTL_SECONDS = 45
|
||||
PROJECT_STORAGE_CACHE: Dict[str, Dict[str, Any]] = {}
|
||||
PROJECT_STORAGE_CACHE_TTL_SECONDS = float(os.environ.get("PROJECT_STORAGE_CACHE_TTL", "30"))
|
||||
|
||||
|
||||
def sanitize_filename_preserve_unicode(filename: str) -> str:
|
||||
@ -1147,6 +1149,10 @@ def get_container_status_api(terminal: WebTerminal, workspace: UserWorkspace, us
|
||||
@with_terminal
|
||||
def get_project_storage(terminal: WebTerminal, workspace: UserWorkspace, username: str):
|
||||
"""获取项目目录占用情况,供前端轮询。"""
|
||||
now = time.time()
|
||||
cache_entry = PROJECT_STORAGE_CACHE.get(username)
|
||||
if cache_entry and (now - cache_entry.get("ts", 0)) < PROJECT_STORAGE_CACHE_TTL_SECONDS:
|
||||
return jsonify({"success": True, "data": cache_entry["data"]})
|
||||
try:
|
||||
file_manager = getattr(terminal, 'file_manager', None)
|
||||
if not file_manager:
|
||||
@ -1160,8 +1166,12 @@ def get_project_storage(terminal: WebTerminal, workspace: UserWorkspace, usernam
|
||||
"limit_label": f"{PROJECT_MAX_STORAGE_MB}MB" if PROJECT_MAX_STORAGE_MB else "未限制",
|
||||
"usage_percent": usage_percent
|
||||
}
|
||||
PROJECT_STORAGE_CACHE[username] = {"ts": now, "data": data}
|
||||
return jsonify({"success": True, "data": data})
|
||||
except Exception as exc:
|
||||
stale = PROJECT_STORAGE_CACHE.get(username)
|
||||
if stale:
|
||||
return jsonify({"success": True, "data": stale.get("data"), "stale": True}), 200
|
||||
return jsonify({"success": False, "error": str(exc)}), 500
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user