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

131 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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 状态]** → 拨测是幂等的(无状态定时任务),重启后立即开始新一轮即可,无需恢复状态