Files
huang 8980e6d999
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m11s
fix: 补全三处轮询覆盖缺口
问题一:protect 轮询任务从未被调度器初始化入队
PollingConfig 新增 protect_check_interval 字段(NULL=不参与),
调度器 initCardsBatch/initCardPolling/requeueCard 补全 protect 队列
初始化逻辑,IotCard 新增 last_protect_check_at 记录上次检查时间。
迁移文件:000102_add_polling_protect_fields

问题二:设备套餐流量耗尽时绑定卡未被停机
UsageService.checkAndTriggerSuspension 新增 carrier_type=device 分支,
通过 DeviceSimBindingStore.ListByDeviceID 查询绑定卡,对每张卡异步
触发 CheckAndStopCard,同步注入 Bootstrap 依赖。

问题三:主套餐过期后不立即停机,依赖下次轮询兜底
PackageActivationHandler.processExpiredPackage 在 updateCarrierSuspended
Status 后,若载体无后续生效套餐,立即异步调用 CheckAndStopCard(iot_card
类型直接触发,device 类型遍历绑定卡),消除停机延迟窗口。

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-02 14:36:24 +08:00

2.1 KiB
Raw Blame History

ADDED Requirements

Requirement: 套餐过期时立即触发绑定卡停机

当主套餐过期处理完成后,若该套餐的载体(卡或设备)无任何后续生效套餐,系统 SHALL 立即异步触发停机检查,不依赖下一次 carddata 轮询兜底。

触发位置PackageActivationHandler.processExpiredPackage 在执行 updateCarrierSuspendedStatus 后,若载体确认无生效套餐,异步调用 StopResumeCallback.CheckAndStopCardiot_card 类型或遍历绑定卡逐一触发device 类型)。

幂等保护CheckAndStopCard 已有"卡已停机则跳过"逻辑,重复触发安全。

与 carddata 轮询的关系此处主动触发为优化项消除延迟窗口carddata 轮询的 checkStopResume 仍作为兜底保障,两者共存不冲突。

Scenario: 主套餐过期且无后续套餐,载体为 iot_card

  • WHEN HandlePackageActivationCheck 检测到一张卡的主套餐已过期(expires_at <= NOW),执行 processExpiredPackage 后确认该卡无待生效或生效中的套餐
  • THEN 系统异步调用 CheckAndStopCard(cardID),将卡停机(network_status = 0stop_reason = "traffic_exhausted"),不等待网关响应

Scenario: 主套餐过期且无后续套餐,载体为 device

  • WHEN HandlePackageActivationCheck 检测到一个设备的主套餐已过期,确认该设备无后续套餐
  • THEN 系统查询设备绑定的所有在线已实名卡,逐一异步触发 CheckAndStopCard

Scenario: 主套餐过期但有排队待生效套餐

  • WHEN processExpiredPackage 处理过期套餐,activateNextPackage 成功激活了下一个待生效套餐
  • THEN 系统不触发停机(因有生效套餐),updateCarrierSuspendedStatus 检查后确认有生效套餐即返回

Scenario: carddata 轮询兜底仍有效

  • WHEN 套餐过期主动停机的异步触发因 gateway 异常失败,卡仍处于在线状态
  • THEN 下一次 HandleCarddataCheckcheckStopResume 检测到在线无套餐,再次尝试停机(兜底保障)