perf(web): optimize API polling frequency and respect page visibility
This commit is contained in:
@@ -37,8 +37,9 @@ function handleNodeChange(val: any) {
|
|||||||
|
|
||||||
function startPolling() {
|
function startPolling() {
|
||||||
stopPolling()
|
stopPolling()
|
||||||
|
if (document.visibilityState === 'hidden') return
|
||||||
loadNodes()
|
loadNodes()
|
||||||
timer = setInterval(loadNodes, 30000)
|
timer = setInterval(loadNodes, 120000) // 放宽至 2 分钟一次
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopPolling() {
|
function stopPolling() {
|
||||||
@@ -48,6 +49,16 @@ function stopPolling() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleVisibilityChange() {
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
if (isMaster.value) {
|
||||||
|
startPolling()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stopPolling()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function checkRoleAndInit() {
|
async function checkRoleAndInit() {
|
||||||
try {
|
try {
|
||||||
const role = await api.settings.get('interconnect', 'interconnect_role')
|
const role = await api.settings.get('interconnect', 'interconnect_role')
|
||||||
@@ -86,10 +97,12 @@ roleBus.on((newRole) => {
|
|||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await checkRoleAndInit()
|
await checkRoleAndInit()
|
||||||
|
document.addEventListener('visibilitychange', handleVisibilityChange)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
stopPolling()
|
stopPolling()
|
||||||
|
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import { api, type AppLog, LOG_CATEGORY, LOG_STATUS } from '@/api'
|
|||||||
import { toast } from 'vue-sonner'
|
import { toast } from 'vue-sonner'
|
||||||
import { format } from 'date-fns'
|
import { format } from 'date-fns'
|
||||||
|
|
||||||
|
import { eventBus } from '@/utils/event-bus'
|
||||||
|
import { LOG_EVENTS } from '@/constants'
|
||||||
|
|
||||||
const notices = ref<AppLog[]>([])
|
const notices = ref<AppLog[]>([])
|
||||||
const unreadCount = ref(0)
|
const unreadCount = ref(0)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -56,12 +59,27 @@ async function markAllAsRead() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let timer: number
|
let timer: number
|
||||||
|
let unsubscribe: () => void
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchNotices()
|
fetchNotices()
|
||||||
timer = window.setInterval(fetchNotices, 60000) // 每分钟拉取一次
|
|
||||||
|
// 订阅 WebSocket 实时事件,在收到新系统日志通知时主动刷新
|
||||||
|
unsubscribe = eventBus.subscribe((msg) => {
|
||||||
|
if (msg.type === LOG_EVENTS.ADDED) {
|
||||||
|
const log = msg.payload
|
||||||
|
if (log && log.category === LOG_CATEGORY.SYSTEM_NOTICE) {
|
||||||
|
fetchNotices()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 10 分钟一次的长轮询作为断连兜底
|
||||||
|
timer = window.setInterval(fetchNotices, 10 * 60 * 1000)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
if (unsubscribe) unsubscribe()
|
||||||
if (timer) clearInterval(timer)
|
if (timer) clearInterval(timer)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ async function loadAgents() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function refreshAgentsOnly() {
|
||||||
|
if (document.visibilityState === 'hidden') return
|
||||||
|
try {
|
||||||
|
const agentList = await api.agents.list()
|
||||||
|
agents.value = agentList
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to poll agent status', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handler functions for Agent
|
// Handler functions for Agent
|
||||||
function viewDetail(agent: Agent) {
|
function viewDetail(agent: Agent) {
|
||||||
agentDetailDialogRef.value?.openDialog(agent)
|
agentDetailDialogRef.value?.openDialog(agent)
|
||||||
@@ -103,13 +113,37 @@ function openEditToken(token: AgentToken) {
|
|||||||
editTokenDialogRef.value?.openEdit(token)
|
editTokenDialogRef.value?.openEdit(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startPolling() {
|
||||||
|
stopPolling()
|
||||||
|
if (document.visibilityState === 'hidden') return
|
||||||
|
refreshTimer = setInterval(refreshAgentsOnly, 30000) // 仅轮询 Agent 在线状态,频率放宽至 30s
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPolling() {
|
||||||
|
if (refreshTimer) {
|
||||||
|
clearInterval(refreshTimer)
|
||||||
|
refreshTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleVisibilityChange() {
|
||||||
|
if (document.visibilityState === 'visible') {
|
||||||
|
refreshAgentsOnly()
|
||||||
|
startPolling()
|
||||||
|
} else {
|
||||||
|
stopPolling()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadAgents()
|
loadAgents()
|
||||||
refreshTimer = setInterval(loadAgents, 10000)
|
startPolling()
|
||||||
|
document.addEventListener('visibilitychange', handleVisibilityChange)
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
if (refreshTimer) clearInterval(refreshTimer)
|
stopPolling()
|
||||||
|
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user