perf: ARM设备性能优化 — in-flight请求去重+后端缓存+仪表盘轮询降频+R2 CDN加速

This commit is contained in:
晴天
2026-03-16 13:55:41 +08:00
parent b11c9533ef
commit 61434137d7
8 changed files with 645 additions and 52 deletions

View File

@@ -220,7 +220,7 @@ let _pollTimer = null
/** 启动 Gateway 状态轮询(每 15 秒,避免过于频繁) */
export function startGatewayPoll() {
if (_pollTimer) return
_pollTimer = setInterval(() => refreshGatewayStatus(), 15000)
_pollTimer = setInterval(() => refreshGatewayStatus(), 30000)
}
export function stopGatewayPoll() {
if (_pollTimer) { clearInterval(_pollTimer); _pollTimer = null }

View File

@@ -19,6 +19,7 @@ const _invokeReady = isTauri
// 简单缓存:避免页面切换时重复请求后端
const _cache = new Map()
const _inflight = new Map() // in-flight 请求去重,防止缓存过期后同一命令并发 spawn 多个进程
const CACHE_TTL = 15000 // 15秒
// 网络请求日志(用于调试)
@@ -56,10 +57,21 @@ function cachedInvoke(cmd, args = {}, ttl = CACHE_TTL) {
logRequest(cmd, args, 0, true)
return Promise.resolve(cached.val)
}
return invoke(cmd, args).then(val => {
// in-flight 去重:同一个 key 的请求正在执行中,复用同一个 Promise
// 避免缓存过期瞬间多个调用者同时 spawn 进程ARM 设备上的 CPU 爆满根因)
if (_inflight.has(key)) {
return _inflight.get(key)
}
const p = invoke(cmd, args).then(val => {
_cache.set(key, { val, ts: Date.now() })
_inflight.delete(key)
return val
}).catch(err => {
_inflight.delete(key)
throw err
})
_inflight.set(key, p)
return p
}
// 清除指定命令的缓存(写操作后调用)
@@ -147,7 +159,7 @@ export async function checkBackendHealth() {
// 导出 API
export const api = {
// 服务管理(状态用短缓存,操作不缓存)
getServicesStatus: () => cachedInvoke('get_services_status', {}, 3000),
getServicesStatus: () => cachedInvoke('get_services_status', {}, 10000),
startService: (label) => { invalidate('get_services_status'); return invoke('start_service', { label }) },
stopService: (label) => { invalidate('get_services_status'); return invoke('stop_service', { label }) },
restartService: (label) => { invalidate('get_services_status'); return invoke('restart_service', { label }) },
@@ -155,7 +167,7 @@ export const api = {
// 配置(读缓存,写清缓存)
getVersionInfo: () => cachedInvoke('get_version_info', {}, 30000),
getStatusSummary: () => cachedInvoke('get_status_summary', {}, 5000),
getStatusSummary: () => cachedInvoke('get_status_summary', {}, 60000),
readOpenclawConfig: () => cachedInvoke('read_openclaw_config'),
writeOpenclawConfig: (config) => { invalidate('read_openclaw_config'); return invoke('write_openclaw_config', { config }) },
readMcpConfig: () => cachedInvoke('read_mcp_config'),

View File

@@ -56,18 +56,23 @@ export function cleanup() {
if (_unsubGw) { _unsubGw(); _unsubGw = null }
}
async function loadDashboardData(page) {
let _dashboardInitialized = false
async function loadDashboardData(page, fullRefresh = false) {
// 分波加载:关键数据先渲染,次要数据后填充,减少白屏等待
// 轻量调用读文件每次都做重量调用spawn CLI/网络请求)只在首次或手动刷新时做
const coreP = Promise.allSettled([
api.getServicesStatus(),
api.getVersionInfo(),
api.readOpenclawConfig(),
// 版本信息:首次加载或手动刷新时才查询(避免 ARM 设备上频繁查 npm registry
(!_dashboardInitialized || fullRefresh) ? api.getVersionInfo() : Promise.resolve(null),
])
const secondaryP = Promise.allSettled([
api.listAgents(),
api.readMcpConfig(),
api.listBackups(),
api.getStatusSummary(),
// getStatusSummary 是最重的调用spawn openclaw status --json只在首次加载时调用
(!_dashboardInitialized || fullRefresh) ? api.getStatusSummary() : Promise.resolve(null),
])
const logsP = api.readLogTail('gateway', 20).catch(() => '')
@@ -111,6 +116,8 @@ async function loadDashboardData(page) {
// 第三波:日志(最低优先级)
const logs = await logsP
renderLogs(page, logs)
_dashboardInitialized = true
}
function renderStatCards(page, services, version, agents, config) {