All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m11s
问题一: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>
35 lines
2.5 KiB
Markdown
35 lines
2.5 KiB
Markdown
## Why
|
||
|
||
轮询系统审计发现 3 个覆盖盲点:`polling:protect` 队列从未被初始化导致保护期一致性检查完全失效;设备级套餐耗尽时停机逻辑分支为空导致绑定卡继续在线消耗流量;套餐过期后卡的网络状态不主动停机,依赖下一轮 carddata 轮询兜底存在最长 60s 的流量泄露窗口。这三个问题均直接影响计费准确性和资源管控。
|
||
|
||
## What Changes
|
||
|
||
- **补全 `polling:protect` 调度器初始化**:在 `PollingConfig` 添加 `protect_check_interval` 字段,在 `tb_iot_card` 添加 `last_protect_check_at` 字段,在 `initCardsBatch`/`initCardPolling`/`requeueCard` 补全 protect 队列写入逻辑,使保护期一致性检查能够定时执行
|
||
- **设备级套餐耗尽触发停机**:在 `UsageService.checkAndTriggerSuspension` 补全 `carrierType == "device"` 分支,查询设备绑定的所有卡并异步触发停机
|
||
- **套餐过期时主动停机**:在 `PackageActivationHandler.processExpiredPackage` 过期主套餐且无后续套餐时,直接异步触发 `CheckAndStopCard`,消除依赖轮询兜底的延迟窗口
|
||
- **修正 `getCardCondition` 死代码**:已实名+离线的卡永远返回 `"real_name"` 而非 `"suspended"`,移除永不可达的分支
|
||
|
||
## Capabilities
|
||
|
||
### New Capabilities
|
||
|
||
- `device-package-exhausted-stop`:设备级套餐(`device_id` 绑定)流量耗尽时,自动触发设备绑定卡的停机操作
|
||
|
||
### Modified Capabilities
|
||
|
||
- `polling-protect-consistency`:补全调度器初始化逻辑,使保护期一致性检查能够按配置间隔定时调度(新增 DB 字段 + 初始化代码)
|
||
- `auto-stop-resume`:新增套餐过期主动停机场景,不再完全依赖下一次 carddata 轮询触发停机
|
||
|
||
## Impact
|
||
|
||
- **数据库迁移**:`tb_polling_config` 新增 `protect_check_interval` 字段;`tb_iot_card` 新增 `last_protect_check_at` 字段
|
||
- **受影响代码**:
|
||
- `internal/polling/scheduler.go` — `initCardsBatch`、`initCardPolling`、`requeueCard`
|
||
- `internal/service/package/usage_service.go` — `checkAndTriggerSuspension`
|
||
- `internal/polling/package_activation_handler.go` — `processExpiredPackage`、`updateIotCardSuspendedStatus`
|
||
- `internal/model/polling.go` — `PollingConfig` struct
|
||
- `internal/model/iot_card.go` — `IotCard` struct
|
||
- `internal/task/polling_handler.go` — `getCardCondition` 死代码清理
|
||
- **无 API 变更**:所有修复为内部调度逻辑,不影响对外接口
|
||
- **需要数据库迁移**:两张表各增一列,向下兼容(nullable)
|