fix: 修复轮询停机连坐、实名逆转防抖及carrier_stopped原因写入缺失三个逻辑缺陷
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m37s

This commit is contained in:
2026-04-20 11:24:56 +08:00
parent fd795d8742
commit 868f5a8ef3
11 changed files with 514 additions and 10 deletions

View File

@@ -0,0 +1,42 @@
## Why
轮询停复机系统存在三个已确认的逻辑缺陷,导致已实名、有套餐的正常卡被错误停机:
1. **连坐问题**:设备下任意一张未实名卡触发 `stopDeviceCards`,会将同设备所有在线卡(包括已实名卡)一并停机,`not_realname` 是单卡属性,不应扩散至设备维度。
2. **无防抖**`polling_realname_handler` 单次检测到实名逆转1→0即立刻触发停机上游运营商接口在数据同步延迟期间可能短暂返回 false导致误停。
3. **carrier 停机无 stop_reason**`polling_cardstatus_handler` 检测到网关侧停机(在线→停机状态变化)时,只更新 `network_status=0`,不写 `stop_reason`,导致卡的 `stop_reason=''``isPollingStopReason` 判断为非轮询原因,卡永久无法被自动复机。
## What Changes
- **修改 `stop_resume_service.go`EvaluateAndAct**:引入 `isDeviceScopeReason()` 判断,`not_realname` 不再触发 `stopDeviceCards`,只停被评估的单卡;`no_package` / `traffic_exhausted` 保持设备维度停机不变。
- **修改 `polling_realname_handler.go`**:实名逆转时不立即停机,改为写入 Redis 计数器;连续 N 次(默认 3 次)检测到逆转后才触发 `EvaluateAndAct`;检测到 true 时重置计数器。
- **新增常量 `StopReasonCarrierStopped`**`pkg/constants/iot.go`):值为 `"carrier_stopped"`,用于标记运营商侧主动停机。
- **修改 `polling_cardstatus_handler.go`**:检测到在线→停机状态变化时,补写 `stop_reason='carrier_stopped'``carrier_stopped` 不进入 `isPollingStopReason`(运营商停机不自动复机,需人工确认)。
- **新增 Redis Key 常量**`pkg/constants/redis.go``RedisPollingRealnameReversalCountKey(cardID)` 用于实名逆转计数。
## Capabilities
### New Capabilities
无新能力,本次为纯缺陷修复。
### Modified Capabilities
- `polling-stop-resume-logic``not_realname` 停机范围从设备维度缩小为单卡维度;新增 `carrier_stopped` 作为合法停机原因(不参与自动复机)。
- `polling-task-handlers`:实名检查 handler 新增逆转防抖逻辑;卡状态检查 handler 新增 carrier 停机原因写入。
## Impact
**受影响代码:**
- `internal/service/iot_card/stop_resume_service.go`
- `internal/task/polling_realname_handler.go`
- `internal/task/polling_cardstatus_handler.go`
- `pkg/constants/iot.go`
- `pkg/constants/redis.go`
**无 DB 变更**(无迁移文件)。
**无 API 变更**(纯内部逻辑调整)。
**现存数据影响:**
- 已处于 `stop_reason=''` 停机状态的卡(如 card_id=2需人工干预设置正确 `stop_reason` 才能自动复机,本次代码修复不回填存量数据。