All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m35s
- 受控系统配置要求 Key 至少三段,原两段式 Key(如 polling.rate_limit_mode)注册被拒,后台不可见、限流器只能使用默认值 - Key 改为 polling.gateway.* 与 polling.stop_resume_record.*;新增迁移 000247 将已落库的旧 Key 改名并保留取值 - 后续提案中规划的开关同步改为三段式(polling.scheduler.mode、polling.stop_resume.queue_enabled)
6.7 KiB
6.7 KiB
1. 迁移与模型
- 1.1 新增成对迁移:建
tb_carrier_rate_limit_group(carrier_id可空表示全局组、group_code、group_name、max_qps、operations、high_priority_operations、reserved_qps、status、审计字段);down 删表。 - 1.2 新增成对迁移:建
tb_gateway_error_classification(关键字、匹配方式、类别、适用操作、优先级、启用状态),写入方案第 6.2 节的初始规则;down 删表。 - 1.3 新增成对迁移:建分区表
tb_card_stop_resume_record(按created_at月分区,主键(id, created_at),DEFAULT 分区,当前月起若干个月分区,索引(card_id, created_at)、(carrier_id, created_at)、(result, created_at));down 删表。 - 1.4 新增成对迁移:
tb_system_config插入module = polling配置项(polling.gateway.rate_limit_mode默认observe、rate_limited_retry_delay、限流累计推迟告警上限、默认 QPS、停复机记录保留月数与提前建分区月数);down 删除这些键。 - 1.5 新增对应 model 与 Store;
internal/infrastructure/systemconfig注册上述键(类型、取值范围、枚举),SystemConfigListRequest.Module枚举增加polling;为 JSON 类型注册项增加结构校验接缝。
2. 网关结构化错误与停复机不重试
- 2.1
internal/gateway:新增GatewayError(类别、业务码、信息、耗时),executeHTTPRequest与业务错误分支返回它并保留现有错误码;上游信息脱敏截断。 - 2.2
flow_card.go:StopCard/StartCard改为maxRetries = 0(同SetCardSpeedTier写法)。 - 2.3 全仓检查对网关错误字符串的解析(如按
Gateway 业务错误: code=匹配),改为读取结构化字段,行为保持一致。
3. 限流器
- 3.1 新增限流器:滑动窗口 Lua(账户组 + 全局组 + 预留额度 +
high_waiting),返回放行或需等待毫秒数;提供立即返回与等待至超时两种调用方式。 - 3.2 限流组配置读取:数据库 → Redis 缓存,变更后即时刷新;按目标卡
carrier_id+ 操作查组,未覆盖或停用回落默认 QPS。 - 3.3 实现限流
AttemptObserver,在BeforeAttempt取名额;与现有审计观察器链式组合;拿不到名额返回ErrRateLimited(结构化错误类别"限流")。 - 3.4 豁免标记:ctx 携带豁免来源;在后台人工点击停复机、通道阈值、自动续费、手动刷新 4 处入口打标记,其余不改。
- 3.5
observe/enforce模式:observe只计数(含本应被限流次数)不拦截;模式读取受控系统配置并即时生效。
4. Asynq 遇限流的重试语义
- 4.1
pkg/queue/server.go:IsFailure对ErrRateLimited返回 false;RetryDelayFunc对其返回rate_limited_retry_delay,其余回落DefaultRetryDelayFunc。 - 4.2 现有轮询 handler(
internal/task/polling_*_handler.go)遇ErrRateLimited按短延迟 Requeue、不计失败、不写失败审计。 - 4.3 限流累计推迟告警:记录任务首次被限流时间,超过上限写告警,任务继续重试。
5. 错误分类与调用计数
- 5.1 错误分类器:按适用操作、启用状态、优先级匹配关键字;规则缓存于 Redis 并在变更后刷新;未命中归业务错误。
- 5.2 网关调用分钟计数:每次尝试结束按"账户 × 操作 × 结果类别"计数并记录耗时分桶,含豁免调用量与本应被限流次数。
- 5.3 卡上最近错误:查询失败时写该卡该检查类型的最近错误(类别、码、信息、时间)。
6. 停复机记录替代审计
- 6.1 每次实际调用上游停机或复机后写停复机记录(来源、场景、尝试序号、结果、错误类别、上游信息、耗时);写入失败只记日志与计数。
- 6.2 系统自动停复机不再写
tb_audit_event与集成日志;后台人工点击停复机保留统一审计并同时写记录。 - 6.3 轮询查询删除集成日志写入(含有变化时的成功记录),业务事实变化的持久化不变。
- 6.4 Worker 定时任务:提前创建未来分区、按保留期删除过期分区,失败写告警。
7. 后台接口
- 7.1 限流组:
GET/POST /polling-rate-limit-groups、GET/PUT/DELETE /polling-rate-limit-groups/:id、PUT /:id/status;保存校验(reserved_qps < max_qps、高优先级属于本组、同账户同操作只属一组);修改仅超级管理员并写统一审计。 - 7.2 错误分类:
GET/POST /gateway-error-classifications、PUT/DELETE /:id、PUT /:id/status、POST /gateway-error-classifications/test。 - 7.3 停复机记录:
GET /card-stop-resume-records(时间范围必填且有上限)、GET /iot-cards/:id/stop-resume-records。 - 7.4 调用量统计:
GET /polling-stats/carriers(实际 QPS、成功率、按类别失败数、p95、本应被限流次数、豁免调用量)与GET /polling-stats/carriers/:carrier_id/trend。 - 7.5 枚举:
GET /polling-options(操作类型、错误类别、匹配方式等)。 - 7.6 同步可执行路由、
cmd/api/docs.go、cmd/gendocs/main.go,运行go run cmd/gendocs/main.go重新生成接口文档。
8. 编译与规范校验
- 8.1
gofmt -w变更文件;go build ./cmd/api ./cmd/worker通过。 - 8.2
openspec validate add-carrier-gateway-rate-limit与openspec doctor --json通过。
9. 测试环境验证(自动化测试为 N/A,按 ENG-TEST-001 在维护者指定测试环境逐项核对)
- 9.1 迁移在测试库执行成功;未来分区与 DEFAULT 分区存在。
- 9.2
observe:超过限流组上限的请求照常发出,统计接口显示本应被限流次数。 - 9.3
enforce:账户组用满时请求被拒;不同账户互不影响;停用组回落默认 QPS;全局组生效;预留额度下停机仍可放行。 - 9.4 内部重试计量:构造查询超时,确认第二次尝试单独取名额。
- 9.5 停复机超时只发一次请求,返回结果未知;后台人工点击不受限流。
- 9.6 Outbox 消费者遇限流:Asynq 重试计数不增加、按短延迟重试;非限流错误按原规则重试;累计推迟超限写告警。
- 9.7 错误分类:测试接口与实际调用的分类一致;"密码错误"归账户配置错误,"已存在"不归已是目标状态。
- 9.8 系统自动停复机只写停复机记录、不写统一审计与集成日志;人工点击两者都写;记录写入失败不影响卡状态回写。
- 9.9 生成的接口文档包含新增接口;
/system-configs?module=polling返回新增配置项且 JSON 结构校验生效。