Files
邹进 42e881576d
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m33s
feat: 卡网关按运营商账户限流并记录停复机调用
- 新增网关限流:按本系统运营商账户(卡 carrier_id)→ 限流组 → 操作限制每秒请求数,每次 HTTP 尝试计量,默认限流、仅后台人工点击/通道阈值/自动续费/手动刷新豁免;支持只统计与拦截两种模式,默认只统计
- Asynq 遇限流不计失败、固定短延迟重试;轮询任务与停复机业务重试遇限流短延迟重排
- 停机、复机不再使用网关内部重试,只发一次请求
- 网关返回结构化错误;新增上游错误分类规则表与测试接口
- 新增按月分区的停复机记录表:系统自动停复机只写记录,不再写统一审计与集成日志;普通轮询查询不再写集成日志
- 新增限流组、错误分类、停复机记录、按账户调用统计与枚举后台接口
- 迁移 000243~000246;同步 OpenSpec 提案(含后续 6 个 change)与技术方案、工程约束
2026-10-24 15:06:41 +09:00

2.3 KiB
Raw Permalink Blame History

Context

依据 docs/engineering/轮询按运营商账户限流技术方案.md 第一部分第 6 节、第四部分"保护期整套机制"。

现状:后台设备停复机设置 protect:device:{id}:stop|start(1 小时,互斥,internal/service/device/service.go:1506,1663);保护期内拒绝相反人工操作;polling:protect 轮询(internal/task/polling_protect_handler.go)方向不一致时 ForceStopCard / ForceStartCard;自动停复机 EvaluateAndAct 不看保护期,造成反复翻转。ProtectCheckSkipsForRealname(stop_resume_unified.go)仅保护期轮询使用。资产 DTO 有 device_protect_status(asset_dto.go:38,144、client_asset_dto.go:75)。

Goals / Non-Goals

Goals: 删除保护期的设置、检查、轮询与展示逻辑;不破坏现有客户端;数据库只加不删。

Non-Goals: 不改停复机业务规则(第 4、6 个 Change);不删 protect_period 常量与历史数据;不删数据库列。

Decisions

  1. 字段保留、固定返回 none:直接删字段会让读取该字段的老版本小程序出错;固定值兼容成本最低。备选"字段 omitempty 后不返回":老客户端读不到同样可能出错,放弃。
  2. 数据库列只改注释:遵循"数据库只加不删";protect_check_interval、last_protect_check_at 列注释标记已废弃,代码中去掉读写。
  3. 存量 Redis 保护期 key 不清理:TTL 只有 1 小时,上线后自然过期;代码不再读取,即使残留也无影响。
  4. Asynq 中已排队的 polling:protect 任务:保留一个空处理函数直接返回成功一个发布周期,避免"未注册任务类型"错误堆积,下一次发布再移除;或上线前确认队列为空。选择保留空处理函数,更稳妥。

Risks / Trade-offs

  • [运营依赖保护期防止误操作] → 已定"规则优先、人工停机无豁免",需要保持停机的关闭轮询(第 7 个 Change 提供批量操作)。
  • [前端仍展示保护期] → 固定 none 时前端显示"无",不报错;前端随后去掉展示。

Migration Plan

  1. 迁移只改列注释。2. 测试环境验证后由维护者发布生产。3. 回退:代码回退即可恢复保护期逻辑,数据库无需回退。