feat(guardian): 强化Gateway守护与Windows启停安全

This commit is contained in:
晴天
2026-03-10 00:28:09 +08:00
parent 743af933bd
commit f32bce12cb
6 changed files with 720 additions and 127 deletions

View File

@@ -3,6 +3,12 @@
* 管理 openclaw 安装状态,供各组件查询
*/
import { api } from './tauri-api.js'
import {
evaluateAutoRestartAttempt,
shouldResetAutoRestartCount,
} from './gateway-guardian-policy.js'
const isTauri = !!window.__TAURI_INTERNALS__
let _openclawReady = false
let _gatewayRunning = false
@@ -17,8 +23,7 @@ let _isUpgrading = false // 升级/切换版本期间,阻止 setup 跳转
let _userStopped = false // 用户主动停止,不自动拉起
let _autoRestartCount = 0 // 自动重启次数
let _lastRestartTime = 0 // 上次重启时间
const MAX_AUTO_RESTART = 3 // 最大连续自动重启次数
const RESTART_COOLDOWN = 60000 // 重启冷却期 60s
let _gatewayRunningSince = 0 // Gateway 最近一次进入稳定运行状态的时间
let _guardianListeners = [] // 守护放弃时的回调
/** openclaw 是否就绪CLI 已安装 + 配置文件存在) */
@@ -36,7 +41,12 @@ export function isUpgrading() { return _isUpgrading }
export function setUserStopped(v) { _userStopped = !!v }
/** 重置自动重启计数(用户手动启动后重置) */
export function resetAutoRestart() { _autoRestartCount = 0; _userStopped = false }
export function resetAutoRestart() {
_autoRestartCount = 0
_lastRestartTime = 0
_gatewayRunningSince = 0
_userStopped = false
}
/** 监听守护放弃事件连续重启失败后触发UI 可弹出恢复选项) */
export function onGuardianGiveUp(fn) {
@@ -134,11 +144,14 @@ function _setGatewayRunning(val) {
_gatewayRunning = val
if (changed) {
if (val) {
// Gateway 恢复运行,重置计数
_autoRestartCount = 0
} else if (wasRunning && !_userStopped && !_isUpgrading && _openclawReady) {
// 仅记录恢复运行时间,避免短暂存活就把重启计数清零
_gatewayRunningSince = Date.now()
} else if (!isTauri && wasRunning && !_userStopped && !_isUpgrading && _openclawReady) {
_gatewayRunningSince = 0
// Gateway 意外停止,尝试自动重启
_tryAutoRestart()
} else if (!val) {
_gatewayRunningSince = 0
}
_gwListeners.forEach(fn => { try { fn(val) } catch {} })
}
@@ -146,16 +159,23 @@ function _setGatewayRunning(val) {
async function _tryAutoRestart() {
const now = Date.now()
// 冷却期内不重复重启
if (now - _lastRestartTime < RESTART_COOLDOWN) return
if (_autoRestartCount >= MAX_AUTO_RESTART) {
console.warn(`[guardian] Gateway 已连续自动重启 ${MAX_AUTO_RESTART} 次,停止守护,请手动检查`)
const decision = evaluateAutoRestartAttempt({
now,
lastRestartTime: _lastRestartTime,
autoRestartCount: _autoRestartCount,
})
if (decision.action === 'cooldown') return
if (decision.action === 'give_up') {
console.warn('[guardian] Gateway 已达到自动重启上限,停止守护,请手动检查')
_guardianListeners.forEach(fn => { try { fn() } catch {} })
return
}
_autoRestartCount++
_lastRestartTime = now
console.log(`[guardian] Gateway 意外停止,自动重启 (${_autoRestartCount}/${MAX_AUTO_RESTART})...`)
_autoRestartCount = decision.autoRestartCount
_lastRestartTime = decision.lastRestartTime
console.log(`[guardian] Gateway 意外停止,自动重启 (${_autoRestartCount}/3)...`)
try {
await api.startService('ai.openclaw.gateway')
console.log('[guardian] Gateway 自动重启成功')
@@ -173,7 +193,15 @@ export async function refreshGatewayStatus() {
const nowRunning = services[0]?.running === true
if (nowRunning) {
_gwStopCount = 0
_setGatewayRunning(true)
if (!_gatewayRunning) {
_setGatewayRunning(true)
} else if (shouldResetAutoRestartCount({
autoRestartCount: _autoRestartCount,
runningSince: _gatewayRunningSince,
now: Date.now(),
})) {
_autoRestartCount = 0
}
} else {
_gwStopCount++
if (_gwStopCount >= 2 || !_gatewayRunning) {

View File

@@ -0,0 +1,38 @@
/**
* Gateway 守护策略
* 纯函数,便于测试自动重启与计数重置规则
*/
export const MAX_AUTO_RESTART = 3
export const RESTART_COOLDOWN = 60000
export const STABLE_RUNNING_MS = 120000
export function evaluateAutoRestartAttempt({
now,
lastRestartTime,
autoRestartCount,
}) {
if (now - lastRestartTime < RESTART_COOLDOWN) {
return { action: 'cooldown' }
}
if (autoRestartCount >= MAX_AUTO_RESTART) {
return { action: 'give_up' }
}
return {
action: 'restart',
autoRestartCount: autoRestartCount + 1,
lastRestartTime: now,
}
}
export function shouldResetAutoRestartCount({
autoRestartCount,
runningSince,
now,
}) {
if (autoRestartCount <= 0) return false
if (!runningSince) return false
return now - runningSince >= STABLE_RUNNING_MS
}