Files
junhong_cmp_fiber/openspec/changes/fix-polling-stop-logic/proposal.md
huang 868f5a8ef3
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m37s
fix: 修复轮询停机连坐、实名逆转防抖及carrier_stopped原因写入缺失三个逻辑缺陷
2026-04-20 11:24:56 +08:00

2.7 KiB
Raw Blame History

Why

轮询停复机系统存在三个已确认的逻辑缺陷,导致已实名、有套餐的正常卡被错误停机:

  1. 连坐问题:设备下任意一张未实名卡触发 stopDeviceCards,会将同设备所有在线卡(包括已实名卡)一并停机,not_realname 是单卡属性,不应扩散至设备维度。
  2. 无防抖polling_realname_handler 单次检测到实名逆转1→0即立刻触发停机上游运营商接口在数据同步延迟期间可能短暂返回 false导致误停。
  3. carrier 停机无 stop_reasonpolling_cardstatus_handler 检测到网关侧停机(在线→停机状态变化)时,只更新 network_status=0,不写 stop_reason,导致卡的 stop_reason=''isPollingStopReason 判断为非轮询原因,卡永久无法被自动复机。

What Changes

  • 修改 stop_resume_service.goEvaluateAndAct:引入 isDeviceScopeReason() 判断,not_realname 不再触发 stopDeviceCards,只停被评估的单卡;no_package / traffic_exhausted 保持设备维度停机不变。
  • 修改 polling_realname_handler.go:实名逆转时不立即停机,改为写入 Redis 计数器;连续 N 次(默认 3 次)检测到逆转后才触发 EvaluateAndAct;检测到 true 时重置计数器。
  • 新增常量 StopReasonCarrierStoppedpkg/constants/iot.go):值为 "carrier_stopped",用于标记运营商侧主动停机。
  • 修改 polling_cardstatus_handler.go:检测到在线→停机状态变化时,补写 stop_reason='carrier_stopped'carrier_stopped 不进入 isPollingStopReason(运营商停机不自动复机,需人工确认)。
  • 新增 Redis Key 常量pkg/constants/redis.goRedisPollingRealnameReversalCountKey(cardID) 用于实名逆转计数。

Capabilities

New Capabilities

无新能力,本次为纯缺陷修复。

Modified Capabilities

  • polling-stop-resume-logicnot_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 才能自动复机,本次代码修复不回填存量数据。