docs: 同步能力规范 — 新增购买/重置后复机 spec,更新停复机和排队激活规范
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m8s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m8s
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -389,3 +389,60 @@ func (s *Service) ResumeCardIfStopped(ctx context.Context, cardID uint) error {
|
||||
- ✅ 并发场景和异常处理
|
||||
- ✅ 性能指标和错误码定义
|
||||
- ✅ 测试场景矩阵和实现参考
|
||||
|
||||
---
|
||||
|
||||
## 迭代更新(fix-stop-resume-lifecycle-engine)
|
||||
|
||||
### MODIFIED Requirement: 流量耗尽自动复机
|
||||
|
||||
系统 SHALL 在套餐激活或流量重置后,对满足以下全部条件的卡自动调用运营商接口复机:
|
||||
1. `stop_reason = "traffic_exhausted"`(仅限流量耗尽停机,手动停机不自动复机)
|
||||
2. `real_name_status = 1`(已完成实名认证)
|
||||
3. `network_status = 0`(当前处于停机状态)
|
||||
|
||||
系统 SHALL 在执行复机前获取 Redis 分布式锁(Key:`card:resume:lock:{cardID}`,TTL 30s),防止并发重复调用 Gateway。
|
||||
|
||||
#### Scenario: 所有条件满足时自动复机
|
||||
- **GIVEN** 卡 C1 满足:`stop_reason=traffic_exhausted`,`real_name_status=1`,`network_status=0`
|
||||
- **WHEN** `ResumeCardIfStopped(ctx, "iot_card", cardID)` 被调用
|
||||
- **THEN** 系统获取分布式锁,调用 `gateway.StartCard`,更新 `network_status=1`,清空 `stop_reason`,释放锁
|
||||
|
||||
#### Scenario: 未实名卡跳过自动复机
|
||||
- **GIVEN** 卡 C2 `stop_reason=traffic_exhausted`,`real_name_status=0`,`network_status=0`
|
||||
- **WHEN** `ResumeCardIfStopped` 被调用
|
||||
- **THEN** 系统记录 WARN 日志,静默跳过,不调用 Gateway,函数返回 nil
|
||||
|
||||
#### Scenario: 手动停机的卡不被自动复机
|
||||
- **GIVEN** 卡 C3 `stop_reason=manual`,`real_name_status=1`,`network_status=0`
|
||||
- **WHEN** `ResumeCardIfStopped` 被调用
|
||||
- **THEN** 系统检测到 `stop_reason != traffic_exhausted`,静默跳过
|
||||
|
||||
#### Scenario: 并发调用时只有一次复机执行
|
||||
- **GIVEN** 卡 C4 满足复机条件,复机操作正在执行(分布式锁被持有)
|
||||
- **WHEN** 第二个 `ResumeCardIfStopped` 调用同时到达
|
||||
- **THEN** 第二个调用获锁失败,直接返回,不调用 Gateway
|
||||
|
||||
#### Scenario: 设备类型载体复机遍历所有绑定卡
|
||||
- **GIVEN** 设备 D1 绑定 3 张卡(C1 已实名停机、C2 已实名停机、C3 未实名停机)
|
||||
- **WHEN** `ResumeCardIfStopped(ctx, "device", deviceID)` 被调用
|
||||
- **THEN** C1 和 C2 自动复机,C3 因未实名跳过
|
||||
|
||||
### ADDED Requirement: 套餐超额停机必须写入 stop_reason 和 stopped_at
|
||||
|
||||
系统 SHALL 在套餐虚流量超额触发停机时(`stopCards` 函数),写入 `stop_reason=traffic_exhausted` 和 `stopped_at` 到 IoT 卡记录。
|
||||
|
||||
#### Scenario: 虚流量超额停机完整写入 DB
|
||||
- **GIVEN** 卡 C1 当月流量超过套餐 `virtual_data_mb` 上限,`network_status=1`
|
||||
- **WHEN** `HandlePackageCheck` 的 `stopCards` 执行
|
||||
- **THEN** Gateway 调用成功后,DB 更新包含:`network_status=0`,`stop_reason=traffic_exhausted`,`stopped_at=now()`,`updated_at=now()`
|
||||
|
||||
### ADDED Requirement: 保护期停机使用常量 stop_reason
|
||||
|
||||
系统 SHALL 在保护期一致性检查停机时,使用 `constants.StopReasonProtectPeriod` 常量(值:`protect_period`)记录 `stop_reason`。
|
||||
|
||||
#### Scenario: 保护期停机写入正确原因
|
||||
- **GIVEN** 设备处于停机保护期,绑定的卡 C1 `network_status=1`(开机状态不一致)
|
||||
- **WHEN** `HandleProtectConsistencyCheck` 触发停机
|
||||
- **THEN** DB 中 `stop_reason=protect_period`(使用常量,非中文硬编码)
|
||||
- **AND** `ResumeCardIfStopped` 调用时因 `stop_reason != traffic_exhausted` 跳过,不会错误触发自动复机
|
||||
|
||||
Reference in New Issue
Block a user