Files
junhong_cmp_fiber/openspec/changes/add-carrier-polling-scheduler/proposal.md
邹进 02a842f066
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m35s
fix: 网关限流系统配置 Key 改为三段式,修复注册失败
- 受控系统配置要求 Key 至少三段,原两段式 Key(如 polling.rate_limit_mode)注册被拒,后台不可见、限流器只能使用默认值
- Key 改为 polling.gateway.* 与 polling.stop_resume_record.*;新增迁移 000247 将已落库的旧 Key 改名并保留取值
- 后续提案中规划的开关同步改为三段式(polling.scheduler.mode、polling.stop_resume.queue_enabled)
2026-10-24 16:17:34 +09:00

5.2 KiB
Raw Blame History

Why

现有轮询按固定 16 个分片 × 5 种类型调度,与运营商账户无关:慢账户占满共用的 Asynq 协程,影响其他账户与其他业务;出队后到投递前崩溃会丢卡;按集合大小背压,单分片超过 50 万后永久停止出队;投递无去重,同卡同类型可能重复执行,同卡不同类型并行执行。业务事件触发的卡观测序列固定"立即、3 分钟、5 分钟"三连查且不受限流,生产 2026-10-22 批量下单 70 张卡形成单秒 177 次的波峰,并与优先轮询重复查询。本 Change 是《轮询按运营商账户限流技术方案》第五部分第 3 节第 5 步。

What Changes

  • 新调度:每个运营商账户 3 个延时队列(停复机预留、优先、普通);卡始终留在队列中,领取时写带租约的处理中标记并推后 score,收尾按下次到期设置 score;崩溃后标记到期自动重新领取,不丢卡。
  • 同卡串行:一张卡一个卡任务,按配置的步骤顺序(默认卡状态 → 流量 → 实名 → 套餐)串行执行已到期的检查类型;每步单独超时,某步失败不影响后续步骤。
  • 分发器每秒按账户领取:账户分发锁保证每轮只有一个实例领取;按执行上限、优先占比、预计网关调用数与本秒剩余 QPS 领取。
  • BREAKING 卡轮询从 Asynq 改为 NSQ 分发:每个账户独立 topic,max_in_flight 控制每进程并发;Redis 是唯一权威状态,NSQ 只做传输。消费前核对派发 token 并抢执行权;执行中续期租约;收尾 Lua 校验 token 写回。
  • 失败处理:按"卡 × 检查类型"记连续失败次数与最近错误,按配置的退避序列重试;限流等待超时不计失败;达到阈值写失败告警(新表 tb_polling_failure_alert),首次成功自动恢复;同账户告警超阈值产生账户级告警。
  • BREAKING 业务事件与读入口改为"请求检查":订单支付、套餐激活、停复机成功、设备操作、自动续费购包,以及 C 端资产详情、后台资产实时状态、实名链接,不再起观测序列;改为把对应检查设为立即到期放入优先队列,同卡多次请求合并,按场景配置延迟确认与冷却时长(新表 tb_polling_check_scene)。OpenAPI 查询保持不触发观测。
  • 优先轮询提示、手动触发队列改为写入账户队列;初始化、生命周期改为操作账户队列与卡到期信息。
  • 运营商账户调度参数(新表 tb_carrier_polling_param):执行上限、每进程 max_in_flight、优先占比等;步骤顺序、单步超时、退避、告警阈值放受控系统配置。
  • 整体切换:受控系统配置 polling.scheduler.mode(legacy / carrier),不按账户灰度;切换时旧任务直接结束、从数据库初始化全部账户新结构后开始领取;可整体回退。
  • 监控改为按运营商账户;下线按 ZCARD 背压、旧并发计数与并发配置接口、旧提示通道。

Capabilities

New Capabilities

  • carrier-polling-scheduler:按账户队列与领取、租约与续期、执行权、同卡串行步骤、NSQ 分发与消费、执行上限与优先占比、失败退避与告警、请求检查与场景配置、整体切换与回退、按账户监控。

Modified Capabilities

  • polling-load-control:删除"轮询全局并发与背压"(由按账户执行上限与限流取代)。
  • polling-operations:删除"轮询并发计数可观测""轮询并发配置覆盖实际任务""轮询任务类型名称可读"(并发配置页下线)。
  • priority-polling-queue:"优先调度与执行提示通道"改为写入运营商账户优先队列。

Impact

  • 依赖:第 1 个 Change(限流器,消费者使用等待模式)、第 3 个 Change(去掉保护期)已上线。
  • 部署:测试环境与生产新增 nsqd + nsqlookupd;go.mod 新增 NSQ 客户端依赖;yaml 增加 NSQ 地址、msg_timeout、租约、续期间隔、分发间隔、卡任务总超时、优雅退出宽限期。
  • 数据库:新增 tb_carrier_polling_param、tb_polling_check_scene(预置场景)、tb_polling_failure_alert;tb_system_config 插入步骤与告警参数、polling.scheduler.mode;tb_polling_concurrency_config 保留不删、表注释标记废弃。
  • 代码:重写 internal/polling/queue_manager.go、scheduler.go、initializer.go、internal/task/polling_*_handler.go(拆为步骤函数)、polling_base.go、internal/service/polling/monitoring_service.go;修改 lifecycle_service.go、priority_manual_service.go、manual_trigger_service.go、polling_priority_claim.go;业务事件 5 处与读入口 3 处改为请求检查;cmd/worker/main.go、internal/bootstrap/* 装配分发器与 NSQ 消费者;删除 concurrency_service.go 及其接口。
  • 接口:新增 /polling-carrier-params、/polling-check-scenes、/polling-failure-alerts(列表、汇总、详情、处理)、/iot-cards/:id/polling-state;/polling-stats 按账户;下线 /polling-concurrency。前端新增调度参数、场景、失败告警页,监控页按账户,下线并发配置页。
  • 行为:业务事件后的检查不再固定三连查,按场景配置;读入口受冷却与限流约束。