85 lines
3.1 KiB
Markdown
85 lines
3.1 KiB
Markdown
实现 Gateway 健康监控(P0-1)。后端 Hermes CLI 封装 + API + 前端页面。
|
||
|
||
## 第一部分: Hermes CLI 服务(真实数据源)
|
||
|
||
创建 backend/app/services/hermes_cli.py:
|
||
- 封装 `hermes gateway status` CLI 调用
|
||
- 用 subprocess.run 执行,解析 JSON 输出
|
||
- 出错时返回空数据 + 日志告警,不抛异常
|
||
- 函数: gateway_status_all() -> list[GatewayInfo]
|
||
- 数据类型: id, name, status(online/offline/warn), downtime_minutes, restarts_today, last_event
|
||
|
||
## 第二部分: Gateway API
|
||
|
||
创建 backend/app/api/gateway.py,全部 require_auth
|
||
|
||
### GET /api/v1/gateway/status
|
||
返回全部 Profile 的 Gateway 状态列表,支持:
|
||
- query param `?status=online|offline|warn` 筛选
|
||
- 每行: name, status(🟢/🔴/🟡), downtime, restarts_today, last_event, profile_type
|
||
- 数据来源: hermes_cli.gateway_status_all()
|
||
|
||
### GET /api/v1/gateway/events
|
||
返回最近 24h 异常事件:
|
||
```json
|
||
[
|
||
{"time": "2026-07-22T18:45", "profile": "monitor", "type": "heartbeat_timeout", "detail": "连续 3 次心跳无响应"},
|
||
{"time": "2026-07-22T14:20", "profile": "feishu-gw", "type": "feishu_disconnect", "detail": "WebSocket 断开 8 分钟"},
|
||
{"time": "2026-07-22T10:30", "profile": "gateway-monitor", "type": "restart", "detail": "Gateway 重启"}
|
||
]
|
||
```
|
||
数据来源: hermes CLI 日志或系统日志解析。暂用占位数据(TODO 标注)。
|
||
|
||
### POST /api/v1/gateway/{profile}/start, /stop, /restart
|
||
Gateway 启停操作:
|
||
- 执行 `hermes gateway start/stop/restart --profile {profile}`
|
||
- 需要 operator 或 owner 角色(require_role("owner","operator"))
|
||
- 返回操作结果 + 写入审计日志
|
||
- 操作前二次确认(前端处理)
|
||
|
||
## 第三部分: 前端 Gateway 页面
|
||
|
||
修改 frontend/src/pages/GatewayPage.tsx:
|
||
|
||
### 顶部: 异常事件时间线
|
||
- Timeline 组件,24h 横向展示
|
||
- 事件类型: 🔴心跳超时 🟠飞书断连 🔵Gateway 重启
|
||
- Hover 显示详情 tooltip
|
||
|
||
### 筛选栏
|
||
- 状态筛选: 全部/在线/离线/异常
|
||
- 蜂型筛选: 全部/工蜂/蜂王
|
||
- 筛选器即时生效(前端过滤,不重新请求)
|
||
|
||
### 状态表
|
||
- Table 组件,10s 轮询 (usePolling hook)
|
||
- 列: Profile 名, 状态 Badge, 掉线时长, 今日重启, 最近异常, 操作
|
||
- 异常行标红: Gateway 连续重启≥3次 或 掉线≥30分钟
|
||
- 操作按钮: 启动/停止/重启 (二次确认 Modal)
|
||
|
||
### 四态覆盖
|
||
- Loading: Skeleton (table 形状)
|
||
- Empty: "全部 Gateway 正常运行 🎉"
|
||
- Error: 错误 + 重试
|
||
- Normal: 数据展示
|
||
|
||
### usePolling hook
|
||
创建 frontend/src/hooks/usePolling.ts:
|
||
```typescript
|
||
import { useEffect, useRef } from 'react'
|
||
export function usePolling(callback: () => void, intervalMs: number, enabled: boolean = true) {
|
||
const savedCallback = useRef(callback)
|
||
useEffect(() => { savedCallback.current = callback }, [callback])
|
||
useEffect(() => {
|
||
if (!enabled) return
|
||
savedCallback.current() // 立即执行一次
|
||
const id = setInterval(() => savedCallback.current(), intervalMs)
|
||
return () => clearInterval(id)
|
||
}, [intervalMs, enabled])
|
||
}
|
||
```
|
||
|
||
注册路由: main.py 添加 `from app.api import gateway; app.include_router(gateway.router, prefix="/api/v1")`
|
||
|
||
完成后提交。
|