7.4 KiB
后端开发
库使用优先级
| 优先级 | 来源 | 典型用途 |
|---|---|---|
| 1 | Bun 内置 API | Bun.serve、bun:sqlite、Bun.spawn、Bun.file、Bun.YAML |
| 2 | es-toolkit | 类型判断、深度比较、错误判断、并发控制、集合操作 |
| 3 | 标准 Web API | Object.fromEntries、Headers、fetch、AbortController |
| 4 | 主流三方库 | cheerio、xpath、@xmldom/xmldom |
| 5 | 自行实现 | 仅在以上都无法满足时 |
新增依赖前必须先检查上述每一层是否已有可用方案。
API 路由开发
路由文件位于 src/server/routes/,每个端点一个文件。路由通过 server.ts 的 Bun.serve({ routes }) 声明式注册,使用 per-method handler 对象。
新增路由步骤:
- 在
src/server/routes/下创建<name>.ts。 - 实现 handler 函数并 export。
- 在
server.ts的routes对象中注册路径和 method handler。 - 在
tests/server/app.test.ts中添加集成测试。
请求参数校验使用 middleware.ts 提供的 validateTargetId、validateTimeRange、validatePagination、validateDashboardWindow、validateRecentLimit、validateMetricsBucket。
共享 helpers
| 函数 | 用途 |
|---|---|
createApiError(error, status) |
构造 API 错误体 |
createHeaders(mode, init) |
创建响应 Headers,生产模式附加安全头 |
createHealthResponse() |
构造健康检查响应 |
formatDuration(ms) |
毫秒转为可读时长字符串 |
jsonResponse(body, options) |
JSON 响应构造 |
mapCheckResult(row, type) |
数据库行转 API CheckResult |
类型规范
- 共享类型以
src/shared/api.ts为唯一源头。 - 严格联合类型优先于宽类型。
- 存储层类型与 API 类型分离。
- checker 具体类型在各自目录定义,中间层通过 base interface 和 registry 完成类型擦除。
- 纯类型导入使用
import type。
配置契约与校验
配置加载流程固定为:unknown -> AuthoringProbeConfig -> NormalizedProbeConfig -> ValidatedProbeConfig -> ResolvedConfig。
| 层级 | 职责 |
|---|---|
| Authoring | 用户 YAML 可书写形态,允许变量引用和 expect 简写 |
| Normalized | 变量替换和 expect 简写展开后的契约校验形态 |
| Validated | 通过契约校验和语义校验的形态 |
| Resolved | checker resolve() 后的运行期配置 |
Ajv 保持严格拒绝模式:allErrors: true、不启用类型强制转换、不注入默认值、不自动删除未知字段。默认对象策略是 additionalProperties: false,只有明确的动态键值表可以开放任意键名。
新增或修改配置字段时必须同步更新 TypeBox schema fragments、probe-config.schema.json、语义 validator、测试和对应用户文档,并运行 bun run schema:check。
数据存储
存储层基于 bun:sqlite,WAL 模式运行,数据库文件位于配置的 dataDir 下。
| 方法 | 用途 |
|---|---|
syncTargets(targets) |
启动期同步 targets |
insertCheckResult() |
写入单条检查结果 |
getTargets() |
查询全部 targets |
getLatestChecksMap() |
批量获取每个 target 的最新检查结果 |
getAllTargetWindowStats(from, to) |
批量获取窗口基础计数 |
getDashboardIncidentStates(from, to) |
获取 Dashboard 窗口状态序列 |
getAllRecentSamples(limit) |
批量获取最近采样 |
getTargetCheckpoints(targetId, from, to) |
获取单目标窗口检查点序列 |
getTargetDurations(targetId, from, to) |
获取单目标成功耗时数组 |
getHistory() |
分页查询历史记录 |
prune(retentionMs) |
清理过期数据 |
数据库只负责存储、筛选、排序、分页、LIMIT 和基础聚合。指标语义在后端应用层实现。
拨测引擎
- 按 interval 分组,每组独立定时触发。
- 使用
es-toolkit/Semaphore限制全局最大并发数。 - 通过
checkerRegistry.get(target.type)选择 runner。 - 每次检查创建
AbortController并按target.timeoutMs触发 abort。 - 状态变化通过注入的
Logger输出结构化日志。
日志模块
后端运行时代码统一通过 Logger 接口输出日志,禁止直接使用 console.*。配置加载失败前使用 ConsoleFallbackLogger。
| 实现 | 用途 |
|---|---|
PinoLoggerWrapper |
生产运行时,封装 Pino、pino-pretty、pino-roll |
NoopLogger |
静默丢弃日志 |
MemoryLogger |
测试替身 |
ConsoleFallbackLogger |
配置加载失败前的降级日志 |
敏感信息会自动 redact authorization、cookie、set-cookie、authToken、key、password、token、apiKey 及其嵌套路径。
expect 系统
共享断言基础设施位于 src/server/checker/expect/。新增或修改 checker 的 expect 字段时,按以下原则选择模型:
| 模型 | 用途 | 典型字段 |
|---|---|---|
| enum / boolean | 状态类结果,结果集合小且稳定 | HTTP status、Cmd exitCode、TCP connected、UDP responded、ICMP alive |
ValueMatcher |
数字指标和字符串元数据 | durationMs、rowCount、finishReason、usage |
ContentExpectations |
返回内容或半结构化内容 | body、stdout、stderr、banner、response、output、result |
KeyedExpectations |
动态键值断言 | headers、DB rows 列值 |
详细 checker 开发流程见 Checker 开发。
错误模型
| 类型 | 结构 | |
|---|---|---|
| API 错误 | { error: "描述", status: <code> } |
|
| CheckFailure | `{ kind: "error" | "mismatch", phase, path, expected?, actual?, message }` |
expect 校验失败记录首个失败原因;网络、超时、进程崩溃统一为 kind: "error"。