1
0
Files
DiAL/openspec/changes/archive/2026-05-09-http-probe-checker/design.md

5.7 KiB
Raw Blame History

Context

Gateway Checker 当前是一个 Bun + React 全栈脚手架,仅包含 demo 验证逻辑(/api/demo 端点 + 前端展示连接状态)。项目已有完整的开发、构建、打包、测试链路。需要将其转化为一个可用的 HTTP 拨测工具。

现有基础设施:

  • Bun 后端:路由框架(createFetchHandler)、服务启动(startServer)、运行时配置解析(readRuntimeConfig
  • React 前端Vite + React + TypeScript开发期通过 Vite proxy 转发 /api/*
  • 构建Vite 前端构建 + Bun 单 executable 打包
  • 测试Bun test + smoke test

Goals / Non-Goals

Goals:

  • 提供完整的 HTTP 拨测能力YAML 配置 → 定时并发拨测 → 结果持久化 → 可视化展示
  • 支持灵活的拨测配置per-target interval、自定义 method/header/body、expect 校验
  • 前端 Dashboard 实时展示:总览统计、目标状态列表、历史记录、延迟趋势图
  • 保持现有项目架构风格和构建打包链路
  • 零外部运行时依赖新增(仅前端 recharts

Non-Goals:

  • 不做告警通知(邮件/短信/Webhook仅 Dashboard 展示
  • 不做数据自动清理/过期策略,保留全部历史记录
  • 不做 SSE/WebSocket 实时推送,用轮询即可
  • 不做拨测目标动态增删(需修改 YAML 后重启)
  • 不做认证/鉴权
  • 不做分布式/集群部署

Decisions

1. 配置管理YAML 统一配置 + 单 CLI 参数

选择所有配置server、数据目录、拨测默认值、目标列表统一到 YAML 文件CLI 只接受一个参数即配置文件路径。

替代方案

  • CLI 参数 + 环境变量覆盖部分配置 → 配置分散,维护成本高
  • TOML 格式 → Bun 无内置支持,需引入依赖

理由

  • 用户明确要求"配置统一到 YAML 文件"
  • Bun.YAML.parse() 内置支持,零依赖
  • 单参数 CLI 最简洁:./gateway-checker ./probes.yaml

2. 数据存储SQLitebun:sqlite

选择:使用 Bun 内置 bun:sqlite 模块WAL 模式运行。

替代方案

  • JSONL 文件追加 → 聚合查询需全表扫描,趋势计算复杂
  • 外部 SQLite 库better-sqlite3→ bun:sqlite 已内置,无需引入

理由

  • 趋势分析需要 AVG(latency) GROUP BY hour 等聚合查询SQL 原生支持
  • bun:sqlite 是 Bun 内置模块,不违反"不引入新依赖"约束
  • WAL 模式支持并发读写
  • .db 文件,便于管理

3. 调度模型:按 interval 分组 + 组内并发

选择:将所有 target 按其 interval 值分组,每组一个 setInterval timer组内使用 Promise.all 并发拨测。

替代方案

  • 全局统一 tick → 无法支持 per-target interval
  • 每个 target 独立 timer → 目标多时 timer 数量大,资源浪费
  • 使用调度队列(如 BullMQ→ 过度设计

理由

  • 支持 per-target interval满足不同服务不同频率的需求
  • 相同 interval 的目标共享 timertimer 数量 = 不同 interval 值的数量
  • 组内并发保证批量效率,组间隔离互不影响

4. 前端更新策略:轮询

选择:前端每 5-10 秒轮询 /api/summary/api/targets

替代方案

  • SSE 服务端推送 → 实现复杂,拨测间隔 15-60s 级别无必要
  • WebSocket → 更复杂,过度设计

理由

  • 拨测间隔本身是 15-60s5s 轮询延迟完全可接受
  • 实现简单,无需维护长连接状态
  • Dashboard 面板按需加载趋势数据(展开详情时请求)

5. 趋势图recharts

选择:引入 recharts 作为前端图表库。

替代方案

  • 纯 SVG 手写 sparkline → 零依赖但代码量大,交互能力有限
  • Chart.js → 非 React 原生,需要 wrapper
  • D3 → 过于底层

理由

  • 用户确认允许引入轻量图表库
  • recharts 是 React 原生图表库,与现有 React 技术栈一致
  • 支持折线图、迷你 Sparkline满足需求
  • 社区活跃,文档完善

6. 目标状态判定模型

选择:两层判定——success(请求是否完成)+ matched(是否符合 expect 规则)。

● UP   = success ✓ && matched ✓
● DOWN = !success || !matched

理由

  • 区分"网络不可达"和"返回了非预期状态码"两种故障场景
  • expect 规则可选,不配置时 matched 默认为 true
  • 前端可以根据 success/matched 分别展示不同故障原因

7. 数据库 Schema 设计

targets 表:从 YAML 同步初始化,运行时只读。 check_results 表:只追加写入,索引 (target_id, timestamp) 加速历史查询。

理由

  • targets 从 YAML 来,不提供运行时动态增删(符合 Non-Goals
  • check_results 追加写入,无需更新/删除,简单可靠
  • 按时间范围查询是最高频操作,复合索引覆盖

Risks / Trade-offs

  • [YAML 格式错误导致启动失败] → 解析时做完整校验,输出清晰错误信息(字段缺失、格式不对、值非法等),提前失败而非运行时出错
  • [并发拨测对目标服务器压力] → 每组内 Promise.all 并发,但同一 group 的 tick 间隔内不会重复拨测。如果用户配置了大量目标且 interval 很短,可能对目标产生压力,这是用户配置责任
  • [SQLite 数据文件增长] → 当前不清理,长期运行会增长。预留清理策略接口,后续可通过配置保留天数
  • [recharts 包体积] → recharts gzip 后约 70KB会增加前端 bundle 大小。对于内部工具可接受
  • [拨测请求超时阻塞] → 使用 AbortController + setTimeout 实现超时,避免单个慢请求阻塞整组
  • [进程重启后丢失 timer 状态] → 拨测是幂等的(无状态定时任务),重启后立即开始新一轮即可,无需恢复状态