## ADDED Requirements ### Requirement: 自动停复机统一经指令队列 在 `polling.stop_resume.queue_enabled` 开启时,系统 SHALL 让套餐步骤、Outbox 卡观测消费者(流量增加、网络状态变化、实名变化)、套餐激活、流量重置、订单支付后、退款后资产处理、套餐到期、运营商账户实名管控修改这些自动入口只请求评估:按统一判断函数(暂停轮询 → 停机条件 → 复机条件 → 通道阈值锁)得出目标状态,需要动作时生成停复机指令并放入卡所属运营商账户的停复机队列,MUST NOT 在入口当场调用网关。请求评估本身只写共享缓存;写入失败 MUST 记日志,并由该卡下一次套餐步骤兜底。后台人工点击、通道阈值、自动续费发起的停复机 MUST 照旧直接执行。开关关闭时各入口 MUST 恢复当场执行;队列中未执行的指令保留,再次开启后继续执行,执行前重新判断。开关 MUST 全局生效,不按运营商账户灰度。 #### Scenario: 订单支付后复机 - **WHEN** 客户支付后套餐生效,卡处于停机且满足复机条件 - **THEN** 订单事务提交后系统生成复机指令,由指令执行器调用上游,支付流程不等待也不起 goroutine #### Scenario: 开关关闭 - **WHEN** 超级管理员关闭 `polling.stop_resume.queue_enabled` - **THEN** 各自动入口恢复当场执行,已在队列中的指令保留不删 ### Requirement: 同卡一条指令与版本号 系统 SHALL 对同一张卡只保留一条停复机指令,新指令覆盖旧指令,方向相反时以最新判断为准、失败计数清零;每次生成或覆盖 MUST 递增指令版本号。执行器领取时记下版本号;收尾时版本号与领取时一致才移除指令,不一致 MUST 保留新指令,并把执行时间设为 max(当前时间, 本卡最近一次停复机调用时间 + 单卡最小重试间隔)。 #### Scenario: 停机执行中客户付费 - **GIVEN** 卡 A 停机指令(版本 1)正在执行 - **WHEN** 执行期间客户付费生成复机指令(版本 2),随后停机成功 - **THEN** 收尾保留复机指令,在单卡最小重试间隔后执行复机 ### Requirement: 指令执行与单卡最小重试间隔 系统 SHALL 优先于卡任务领取停复机指令,领取数不超过停复机所在限流组本秒剩余 QPS 与账户停复机执行上限减执行中数。同一张卡两次停复机网关调用(停机与复机合计)间隔 MUST 不小于账户配置的单卡最小重试间隔,未到间隔时推后执行时间、不发起调用。执行前系统 MUST 按指令记录的场景重新判断,已是目标状态或条件不再满足则结束指令。网关只调用一次,不 sleep 重试;成功后按现有回写更新卡状态、停机原因与网络状态序列,并写停复机记录。 #### Scenario: 停机后几分钟内购买套餐 - **GIVEN** 卡 A 5 分钟前被停机,单卡最小重试间隔 10 分钟 - **WHEN** 客户购买套餐生成复机指令 - **THEN** 系统在停机后满 10 分钟时才调用复机,期间不调用上游 #### Scenario: 执行前已是目标状态 - **WHEN** 停机指令执行前重新判断发现卡已停机 - **THEN** 系统结束指令,不调用上游停机 ### Requirement: 停复机结果未知的确认 停复机调用超时、连接失败或上游返回"调用成功""操作进行中""请求被合并"等已受理类频率限制时,系统 SHALL 置待确认标记并保留指令,在账户配置的确认延迟后再次领取:先按规则重新判断,条件不再满足则结束;否则查一次卡状态(受限流、不受单卡最小重试间隔约束),已是目标状态则按成功回写并结束;不是目标状态则清除待确认,满足单卡最小重试间隔时重新调用停复机,否则推后;查状态失败 MUST 保持待确认并按退避重查,不发起停复机。连续结果未知达到阈值时写失败告警,指令不丢弃。 #### Scenario: 超时后确认已停机 - **WHEN** 停机超时,确认延迟后查状态显示已停机 - **THEN** 系统按成功回写,结束指令,停复机记录结果为确认成功 #### Scenario: 查状态也失败 - **WHEN** 确认查询失败 - **THEN** 系统不发起停机,按退避再次查询 ### Requirement: 停复机失败分类处理 系统 SHALL 按错误分类处理停复机失败:频率限制不计连续失败,按单卡最小重试间隔与上游窗口退避;终态不可操作不重试、结束指令、写告警(标记自动关闭轮询的终态按 `card-stop-resume` 关闭该卡轮询),停机方向且上游已不可用时按目标状态视为已停;已是目标状态按成功处理;账户配置错误首次即产生账户级告警;临时故障、网络超时、业务错误计入连续失败按退避重试。达到告警阈值后写失败告警,指令 MUST NOT 丢弃,按最长退避继续重试。 #### Scenario: 停机持续失败 - **WHEN** 停机连续失败达到阈值 - **THEN** 系统写停复机方向的失败告警,指令保留并按最长退避继续重试 ### Requirement: 设备维度判断合并 需要设备维度判断时,系统 SHALL 不在调用方当场判断,而是请求一次设备判断:递增设备判断版本号、把请求场景加入设备的场景集合、设备加入设备判断队列(同一设备只有一个成员)。设备判断执行时 MUST 抢设备判断锁(锁内不调网关),读取最新数据按统一判断函数判断(各卡按所属运营商账户判断实名,暂停轮询按场景集合判断),需要动作时为设备下每张卡生成指令(记录触发场景)进入各卡所属账户的停复机队列。收尾时只移除本次已处理的场景;版本号变大时 MUST 用最新数据再判断一次。同一设备同一时刻只有一个判断在执行。旧路径正在对该设备执行停复机时(持现有设备锁),设备判断 MUST 推后、不并行执行。 #### Scenario: 跨账户设备流量用完 - **GIVEN** 设备 D 有 3 张卡分属联通、移动、广电账户 - **WHEN** 卡 1 流量入账使设备流量用完,同时卡 2 的消费者读到扣减前数据 - **THEN** 两次请求合并为一次设备判断,按最新数据为 3 张卡各生成停机指令,进入各自账户队列 #### Scenario: 到期与普通请求合并 - **GIVEN** 设备 D 已暂停轮询 - **WHEN** 设备套餐到期请求与一次普通轮询请求在判断前合并 - **THEN** 场景集合含"套餐到期",系统按套餐失效放行停机 ### Requirement: 自动入口的改造语义 系统 SHALL 按以下语义改造自动入口:套餐激活、流量重置、订单支付后在业务事务提交后请求评估,不起 goroutine 当场复机;退款后资产处理在资产无可用主套餐时请求评估(设备按设备维度判断),请求写入成功即标记资产后处理完成,MUST NOT 调用人工停机接口,MUST NOT 因停机失败触发 Outbox 重投或补偿扫描;运营商账户实名管控由 0 改为 1 时对该账户在线且未实名的卡、由 1 改为 0 时对停机且未实名的卡批量请求评估(设备卡按设备),按账户 QPS 平滑执行;卡或设备恢复轮询时不另加触发,由套餐步骤随即评估。 #### Scenario: 退款后上游终态 - **WHEN** 退款后资产无可用主套餐,卡在上游已销户 - **THEN** 退款资产后处理标记完成,停机指令按终态结束并告警,不再反复补发 #### Scenario: 开启实名管控 - **WHEN** 超级管理员把账户 A 实名管控由 0 改为 1 - **THEN** 系统对 A 下在线未实名的卡请求评估,停机按 A 的停复机 QPS 逐步执行