Files
hive-manage-v3/docs/superpowers/plans/phase-3-spec.md
T

3.1 KiB
Raw Blame History

实现 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 异常事件:

[
  {"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:

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")

完成后提交。