Files
junhong_cmp_fiber/docs/7月迭代/新增需求/01-数据同步触发与轮询优化.md
2026-07-16 15:08:07 +08:00

27 KiB
Raw Blame History

新增需求 01数据同步触发与轮询优化

状态:已合并至标准评审稿,本文保留为实施明细。 评审主文档:../7月迭代技术方案-标准评审稿.md 范围IoT 卡实名、流量、网络状态和设备实时数据同步。

一、已确认决策

  1. 轮询、运营商回调、业务事件触发是三条相互隔离的自动同步通道。
  2. 轮询始终保留,负责回调失效、事件漏网和上游偶发失败时的最终兜底。
  3. 资产是否轮询只保留现有全局开关 enable_polling;不再设计“实名资格、流量资格、状态资格”等业务资格开关。
  4. 轮询优化只区分活跃卡和不活跃卡,通过不同轮询间隔降低无效请求,不因业务类型直接永久排除某类卡。
  5. 行业卡是否需要实名不能由 card_category=industry 推断,统一以运营商 realname_link_type 判断。
  6. 业务事件触发不是新增一个显式同步接口,而是埋点到关键查询、停复机、支付、实名和设备操作用例中。
  7. 每次事件默认形成三个独立尝试:立即、事件发生后 3 分钟、事件发生后 5 分钟;三次结束后由常规轮询继续兜底。
  8. 不设置统一五分钟冷却。重复请求控制拆成同场景触发合并、单卡请求互斥和运营商最小请求间隔Gateway 超频只记录当前失败,不建立退避状态。
  9. 运营商实名回调百分百信任,不做来源真实性校验;但必须经过防腐层完成报文解析、标识转换和状态语义转换。
  10. 解除实名第一版不修改业务状态,只保留回调入口、写入统一集成审计并返回运营商要求的成功报文。
  11. 三条自动通道和现有手动刷新接口共享同一套“获取上游观测并应用到业务”的 DDD 用例,禁止各入口直接更新卡字段。
  12. 同步执行记录属于全局审计的 Integration Log不在本方案新建 tb_card_sync_execution 或独立同步监控系统。
  13. 本次迁移触碰到的旧实名、流量和状态写逻辑必须删除或改为调用新用例,不保留长期双实现。

二、现状问题

当前代码存在以下明确问题:

  • internal/task/polling_realname_handler.go 直接跳过所有行业卡,与“是否实名由运营商特性决定”冲突。
  • PollingRealnameHandlerPollingCarddataHandlerPollingCardStatusHandler 同时承担 Gateway 查询、字段更新和业务联动。
  • internal/service/iot_card/service.go:RefreshCardDataFromGateway 又实现一套实名、流量和网络状态同步。
  • ManualUpdateRealnameStatus 单独实现实名状态变更联动,无法保证与轮询、回调行为一致。
  • ClientRealnameHandler、部分设备 Handler 直接调用 Gateway业务事件无法在统一用例边界埋点。
  • 现有获取实名链接后的自动检查借用了 ManualTriggerService,把系统事件伪装成平台用户手工操作。
  • 调度任务载荷只有 card_id,缺少触发场景、来源、序列和关联链路。
  • last_sync_time 被实名、流量和状态共同覆盖,无法说明最后同步了什么。
  • 现有显式刷新接口已经存在,再增加 /card-sync/requests 只会形成重复入口。

因此,本次不是增加更多同步 Service而是先收口写侧用例再把轮询、回调和事件触发接入同一边界。

三、目标架构

flowchart LR
    Polling[轮询调度] --> Activity[按活跃度计算下次间隔]
    Activity --> Request[RequestCardObservation]

    Business[关键业务用例] --> Trigger[CreateSyncTriggerSeries]
    Query[关键查询用例] --> Trigger
    Trigger --> A1[立即尝试]
    Trigger --> A2[3分钟后尝试]
    Trigger --> A3[5分钟后尝试]
    A1 --> Gate[请求协调器]
    A2 --> Gate
    A3 --> Gate
    Gate --> Request

    Manual[现有手动刷新接口] --> Request

    Callback[运营商实名回调] --> ACL[运营商防腐层]
    ACL --> RealObs[标准实名观测]

    Request --> Gateway[Gateway Adapter]
    Gateway --> Observation[标准化观测值]
    RealObs --> Apply[ApplyCardObservation]
    Observation --> Apply

    Apply --> Card[保存卡状态]
    Apply --> Events[记录领域事件和 Outbox]
    Events --> Package[套餐激活与流量扣减]
    Events --> StopResume[停复机评估]
    Events --> ActivityMark[更新活跃标记]
    Request --> Integration[统一 Integration Log]
    ACL --> Integration
    Events --> Audit[关键业务 Audit Event]

各入口边界:

入口 是否调用 Gateway 执行方式 作用
轮询 异步、持续重排 最终一致性兜底
运营商回调 同步应用状态,联动异步可靠投递 实名成功急速通道
业务事件触发 异步 0/3/5 三次 Best Effort 提高正在操作资产的命中概率
现有手动刷新 保持现有响应契约 用户明确要求立即刷新

手动刷新不是第四种自动策略,也不能被业务埋点调用。

四、DDD 设计

4.1 目录

internal/
├── domain/cardstate/
│   ├── card.go                    卡状态聚合及状态转换
│   ├── observation.go             实名、流量、网络状态观测值
│   ├── events.go                  状态变化领域事件
│   └── repository.go              聚合仓储接口
├── application/cardsync/
│   ├── request_observation.go      查询 Gateway 并获取标准观测
│   ├── apply_observation.go        在事务内应用观测和领域事件
│   ├── create_trigger_series.go    创建事件触发序列
│   ├── execute_trigger_attempt.go  执行单次阶梯尝试
│   ├── mark_activity.go            更新活跃标记
│   └── refresh_asset.go            承接现有显式刷新接口
├── infrastructure/adapter/gateway/
│   └── card_observation_adapter.go 复用现有 Gateway Client
├── infrastructure/adapter/carrier_callback/
│   ├── translator.go               防腐层统一接口
│   ├── cmcc.go
│   ├── cucc.go
│   └── ctcc.go
├── infrastructure/messaging/cardsync/
│   ├── trigger_publisher.go         Outbox/Asynq 任务发布
│   └── trigger_handler.go           阶梯任务处理器
└── query/cardsync/
    └── activity_query.go            活跃状态和下次轮询查询

4.2 实名要求判断

不得继续使用以下判断:

if card.CardCategory == constants.CardCategoryIndustry {
    // 跳过实名
}

现有 tb_carrier.realname_link_type 可以直接决定该运营商接入是否需要实名,不新增重复能力字段:

realname_link_type 实名要求 实名入口
none 不需要实名 不提供实名链接,不创建实名查询任务
template 需要实名 使用模板生成实名链接
gateway 需要实名 调用 Gateway 获取实名链接
  • 资产 realname_policy 只决定“先实名后购买”或“先购买后实名”的业务顺序。
  • realname_link_type=none 时,资产有效实名策略统一视为 none
  • realname_link_type!=none 时,资产 realname_policy=none 属于冲突数据,发布前列出并修正,禁止运行时静默选择其中一方。
  • card_category 只保留业务分类和展示用途,不参与实名轮询、复机或套餐激活判断。

运营商是否配置回调 Adapter 只影响有没有回调急速通道,不改变 realname_link_type 对实名要求的判断。

4.3 标准化观测值

type SyncSource string

const (
    SyncSourcePolling         SyncSource = "polling"
    SyncSourceBusinessEvent   SyncSource = "business_event"
    SyncSourceOpenAPI         SyncSource = "open_api"
    SyncSourceManualRefresh   SyncSource = "manual_refresh"
    SyncSourceCarrierCallback SyncSource = "carrier_callback"
)

type ObservationMeta struct {
    Source        SyncSource
    TriggerScene  string
    TriggerSeries string
    Attempt       int
    Provider      string
    ObservedAt    time.Time
    RequestID     string
    CorrelationID string
}

type RealnameObservation struct {
    CardID   uint
    ICCID    string
    Verified bool
    Meta     ObservationMeta
}

type TrafficObservation struct {
    CardID           uint
    GatewayReadingMB float64
    Meta             ObservationMeta
}

type NetworkObservation struct {
    CardID      uint
    CardStatus  string
    Extend      string
    GatewayIMEI string
    Meta        ObservationMeta
}

领域层不使用 map[string]any 传递核心状态,防止不同入口遗漏字段或混淆单位。

4.4 观测应用规则

ApplyCardObservation 是唯一允许把上游数据写入卡领域状态的入口:

  1. 加载并锁定卡聚合。
  2. 根据观测类型执行实名、流量或网络状态规则。
  3. 状态未变化时只更新时间和观测来源,不重复产生业务事件。
  4. 状态变化时保存聚合,并在同一事务写 Outbox 和关键 Audit Event。
  5. 实名 0 -> 1 产生 CardRealnamed,触发卡级/设备级套餐激活和停复机评估。
  6. 流量正增量产生 CardTrafficIncreased,由套餐应用服务扣减套餐流量。
  7. 网络状态变化产生 CardNetworkStatusChanged,由停复机策略重新评估。
  8. 状态变化或流量增加时更新卡活跃标记。

解除实名回调不构造 Verified=false 观测,不修改卡状态。

五、轮询优化:只做活跃度调频

5.1 全局开关

enable_polling 是资产是否参与自动轮询的唯一业务开关:

  • false:从所有轮询队列移除,事件触发也不因此失效;用户主动操作仍可触发 Best Effort 同步。
  • true:按照活跃度和运营商能力进入对应 Gateway 查询队列。
  • 设备关闭轮询时,继续沿用现有设备与绑定卡级联规则。

不再提供“实名轮询开关、流量轮询开关、状态轮询开关”给业务人员配置。

5.2 活跃标记

卡增加或维护以下轮询调度字段:

polling_activity_level       active / inactive
last_polling_activity_at     最后活跃时间
last_polling_activity_scene  最后活跃场景
last_upstream_change_at      上游观测最后发生变化时间

以下情况标记为活跃:

场景 说明
C 端、后台或开放接口查询资产实时信息 表明当前有人关心该资产
获取实名链接 表明即将发生实名操作
停机、复机、切卡、重启、恢复出厂设置 表明上游状态正在变化
套餐支付、激活、失效或流量重置 可能影响流量和停复机
运营商回调 上游已发生变化
轮询发现实名、流量或网络状态变化 卡当前确实活跃

卡在配置时间内没有业务活动,且连续轮询未发现上游变化时转为 inactive。该判断在每次重排队时完成,不新增全表扫描任务。

第一版建议配置而非写死:

inactive_after = 30m
active_realname_interval = 现有实名默认间隔
active_traffic_interval = 现有流量默认间隔
active_network_interval = 现有状态默认间隔
inactive_realname_interval = 15m
inactive_traffic_interval = 15m
inactive_network_interval = 15m

现有 tb_polling_config 的有效间隔迁移为活跃卡默认值,但不再按 card_condition/card_category 匹配多套业务资格。第一版调整为一套全局活跃/不活跃间隔;运营商配置只描述接口能力和上游限频,不再决定某张卡是否“有资格”轮询。上线前使用生产数据做只读测算,确认 Gateway QPS 和最长兜底延迟后再调整数值。

5.3 调度规则

enable_polling=false
  -> 不入自动轮询队列

enable_polling=true + active
  -> 使用全局活跃间隔

enable_polling=true + inactive
  -> 使用全局不活跃间隔

realname_link_type=none
  -> 不创建实名查询任务

已实名卡仍可低频查询实名状态,以发现上游实名逆转;未实名行业卡也不能因卡类别被排除。

六、业务事件触发

6.1 不是新增接口

本需求不新增 POST /api/admin/card-sync/requests,也不新增独立“事件同步”按钮。

现有接口保持:

POST /api/admin/assets/:identifier/refresh
POST /api/c/v1/asset/refresh

现有批量轮询运维接口可以保留,但必须改为调用新的 Application 用例,不再自行维护另一套同步逻辑。

业务事件触发由 Application UseCase 或 Query 完成后调用内部端口:

type SyncTriggerCommand struct {
    Scene         string
    ResourceType  string
    ResourceID    uint
    CardIDs       []uint
    SyncTypes     []string
    ExpectedState map[string]any
    Source        SyncSource
    RequestID     string
    CorrelationID string
}

写操作在业务成功后触发;有数据库事务的关键写操作通过 Outbox 发布触发事件,避免提交成功后进程退出造成埋点丢失。读操作只查询本地快照,不等待 Gateway在返回前 Best Effort 写入 Asynq入队失败不得改变原接口响应。

6.2 阶梯式尝试

每个触发序列默认创建三个 Asynq 任务:

尝试 计划时间 Asynq 自动重试
1 立即 0
2 事件发生后 3 分钟 0
3 事件发生后 5 分钟 0

每次任务都有确定性的 series_id + attempt 幂等键。单次失败不会额外重试,也不会取消后续两次;三次结束后由常规轮询兜底。

存在明确预期状态时允许提前完成序列:

  • 复机后已观测为开机。
  • 停机后已观测为停机。
  • 获取实名链接后已通过回调或查询确认实名。
  • 切卡后设备当前卡已经是目标 ICCID。

序列提前完成后,剩余任务启动时检查状态并直接记为 completed,不再请求 Gateway。

6.3 关键埋点

埋点放在应用用例成功边界,不散落在 Handler 的 response.Success 前后。现有 Handler 直接调用 Gateway 的路径在迁移时收口到 Application。

现有入口/用例 触发内容 预期状态
GET /api/c/v1/asset/info 资产绑定卡的实名、流量、网络状态
GET /api/admin/assets/:identifier/realtime-status 对应卡或设备绑定卡的实时数据
GET /api/open/v1/cards/traffic 流量
GET /api/open/v1/cards/status 网络状态
GET /api/open/v1/cards/realname-status 实名
GET /api/open/v1/devices/traffic 设备信息、绑定卡流量
C 端和后台获取实名链接 实名 已实名
后台、C 端、开放接口停机/复机成功 网络状态 停机或开机
自动停复机 Gateway 调用成功 网络状态 停机或开机
订单支付、钱包购买套餐、套餐激活成功 实名、流量、网络状态
设备切卡或切换模式成功 设备信息、源卡和目标卡网络状态、目标卡流量 目标 ICCID
设备重启、恢复出厂设置、WiFi 设置成功 设备信息、绑定卡网络状态
卡绑定/解绑、设备或卡分配/回收 只标记活跃;确有上游操作时再创建同步序列

补充规则:

  • POST /api/admin/assets/:identifier/refreshPOST /api/c/v1/asset/refresh 已经直接同步,不再额外创建 0/3/5 序列。
  • 运营商实名回调直接应用观测,不再反查 Gateway回调成功后终止相同卡的待执行实名序列。
  • 轮询发现状态变化只更新活跃标记,不反向创建新的事件序列。
  • 同一次设备操作涉及多张绑定卡时使用同一 correlation_id,但每张卡独立限流和记录结果。

6.4 冷却、合并与限流

不使用一个固定五分钟 SET NX 键拦截所有事件。请求协调器只处理同场景合并、单卡互斥和最小请求间隔Gateway 返回超频后不建立额外退避状态。

同场景触发合并

cardsync:series:{scene}:{resource_type}:{resource_id}:{sync_type}
  • 同一场景、同一资源、同一同步类型已有未结束序列时,新触发合并到原序列。
  • 合并只防止页面轮询、开放接口重试等重复创建大量 0/3/5 任务。
  • 停复机、支付、切卡等不同业务场景不会被一个查询场景长期压制。
  • 序列键只覆盖最后一次计划任务和短暂缓冲,不作为全局五分钟冷却。

单卡请求互斥

cardsync:inflight:{provider}:{sync_type}:{card_id}
  • 只覆盖一次 Gateway 请求的执行时间TTL 为请求超时加安全余量。
  • 防止轮询、手动刷新和事件任务同时请求并重复应用同一观测。
  • 轮询命中互斥时延迟短时间重排;事件尝试命中互斥时只跳过当前尝试,后续阶梯任务仍存在。

运营商最小请求间隔

最小间隔按运营商接入和接口类型配置,例如实名、流量、状态可以不同,不能统一写死为五分钟。

  • 默认兜底值建议为 10 秒,仅用于阻止近乎同时的重复调用。
  • 如果上游明确给出更严格限制,以运营商配置为准。
  • 高价值状态变更事件命中最小间隔时,延迟到最近允许时间,不直接丢弃整个序列。

超频结果处理

  • Gateway 返回超频时,当前尝试记录为 rate_limited 后直接结束。
  • 不记录 blocked_until,不读取 Retry-After,也不执行 30s/60s/120s 退避。
  • 不为当前尝试额外补发任务,原定 3 分钟、5 分钟尝试保持不变。
  • 后续轮询仍按正常调度时间继续,是否再次超频由当时上游实际情况决定。
  • 轮询、事件和手动刷新仍共享本系统的并发控制,避免本系统自身在同一时刻并发打满 Gateway。

因此“5 分钟”是第三次尝试的计划时间,不是禁止新业务事件同步的冷却时间。

6.5 开放接口行为

开放接口继续返回本地快照,不等待 Gateway

sequenceDiagram
    participant Agent as 代理系统
    participant API as Open API
    participant DB as PostgreSQL
    participant Trigger as CreateSyncTriggerSeries
    participant Worker as Sync Attempt Worker

    Agent->>API: 查询实名/状态/流量
    API->>DB: 查询当前本地快照
    DB-->>API: 当前数据
    API-->>Agent: 按现有结构立即返回
    API->>Trigger: Best Effort 创建 0/3/5 序列
    Trigger-->>Worker: 同场景重复请求自动合并

七、运营商实名回调防腐层

7.1 防腐层职责

“百分百信任回调”表示信任其业务结论,不表示让运营商报文直接进入领域模型。

type CarrierRealnameCallbackTranslator interface {
    TranslateSuccess(body []byte) (CarrierRealnameNotice, error)
    TranslateRemoval(body []byte) (CarrierRealnameRemovalNotice, error)
    SuccessResponse() CallbackResponse
    FailureResponse(err error) CallbackResponse
}

各运营商 Adapter 负责:

  • 解析 JSON、XML 或表单字段。
  • 提取并校验 19/20 位 ICCID、MSISDN 等标识。
  • 把运营商状态码翻译为“实名成功”或“解除实名通知”。
  • 屏蔽运营商字段名、状态码和成功响应格式。
  • 生成脱敏 Integration Log 摘要。

领域层只接收标准 RealnameObservation,不依赖移动、联通、电信的报文结构。

ICCID 19/20 位解析

回调必须复用现有双列存储和按长度路由规则:

收到 19 位 ICCID
  -> 原值查询 tb_iot_card.iccid_19

收到 20 位 ICCID
  -> 原值查询 tb_iot_card.iccid_20

收到其他长度
  -> invalid_payload不进入实名用例
  • 先去除首尾空白,再调用现有 ICCID Validator只接受 19 位或 20 位字母数字值。
  • 禁止把 20 位回调值截成 19 位后降级查询。
  • 禁止为 19 位值自行补第 20 位校验位。
  • 查询 Miss 时不切换另一列重试,记录原始长度、运营商和脱敏 ICCID 摘要。
  • 复用 IotCardStore.GetByICCID 的长度路由语义;防腐层只负责提取和校验,不自己拼接模糊 SQL。
  • iccid_19 必须在未删除卡中保持唯一。发布前检查重复前缀并建立 Partial Unique Index避免 19 位回调错误命中任意一张卡。
  • Repository 查询若发现多条匹配必须返回冲突,不允许使用 First 静默选择。
  • Integration Log 的 resource_key 保存回调原始 19/20 位值,展示时按审计权限脱敏。

7.2 路由

POST /api/callback/carriers/cmcc/realname
POST /api/callback/carriers/cucc/realname
POST /api/callback/carriers/ctcc/realname

POST /api/callback/carriers/cmcc/realname/remove
POST /api/callback/carriers/cucc/realname/remove
POST /api/callback/carriers/ctcc/realname/remove
  • 成功回调:防腐层转换后直接调用 ApplyCardObservation(Verified=true)
  • 解除回调:只写统一 Integration Log状态记为 ignored,不修改卡状态。
  • 广电或其他没有回调能力的接入继续依赖事件和轮询。
  • 不验证回调是否真的来自运营商,不执行 Gateway 二次查询。
  • 不调用旧平台 inner_callback、第三方推送或删除实名接口。

7.3 响应原则

  • 找到卡并应用成功:返回运营商要求的成功报文。
  • 重复成功回调:幂等返回成功,不重复激活套餐。
  • 找不到卡Integration Log 记 not_found,仍返回成功,避免无意义高频重推。
  • 报文无法解析:记录 invalid_payload;若运营商有固定成功应答要求,仍按接入约定返回,避免不可控重试风暴。
  • 状态已落库但异步联动失败:返回成功,联动通过 Outbox 重试。

八、统一审计契约

同步运行数据不在本方案定义独立表和独立页面,统一由 04-全局多视角审计方案.md 管理。

本模块需要向审计系统提供:

记录 进入位置
每次 Gateway 实际请求或被限流、合并的尝试 Integration Log
每次运营商实名/解除实名回调 Integration Log
实名、流量、网络状态发生业务变化 Audit Event + Integration Log
手动刷新、手动实名修改 Audit Event + Integration Log
连续失败达到阈值、超频持续异常 风险 Audit Event
普通高频轮询成功且数据未变化 仅 Integration Log

必须携带:

provider / operation / resource / trigger_scene / trigger_series
attempt / result / duration / request_id / correlation_id
state_changed / provider_code / error_summary

资产详情的“查看同步轨迹”跳转审计中心外部集成视角,不再建设 /operations/card-sync 独立监控页。

九、接口和前端调整

9.1 后端接口

本需求不新增显式同步接口。

现有手动刷新接口内部改为调用 RefreshAssetUseCase,响应结构和权限保持不变。现有轮询监控接口增加:

  • 活跃卡数量、不活跃卡数量。
  • 各活跃级别的实际轮询 QPS。
  • 因互斥或运营商最小间隔而延迟的任务数,以及 Gateway 超频失败次数。

资产实时状态或详情 Query 增加可选调度信息:

{
  "polling": {
    "enabled": true,
    "activity_level": "active",
    "last_activity_at": "2026-07-15T10:00:00+08:00",
    "last_activity_scene": "client_asset_info",
    "next_poll_at": "2026-07-15T10:01:00+08:00"
  }
}

同步明细查询复用全局审计接口:

GET /api/admin/audit/integrations
    ?provider=gateway
    &resource_type=iot_card
    &resource_key=89860...
    &trigger_scene=
    &trigger_series=

9.2 前端

保留现有资产刷新按钮,不新增第二个同步按钮。

资产详情增加紧凑的轮询状态展示:

自动轮询:已开启
活跃状态:活跃
最后活跃2分钟前C端资产详情
下次兜底约1分钟后
同步轨迹:查看

“查看”跳转:

/operations/audit?tab=integrations&resource_type=iot_card&resource_key={identifier}

轮询监控页只增加活跃/不活跃分布和限流状态,不重复实现 Integration Log 表格、详情抽屉和导出。

十、代码迁移范围

10.1 必须删除或收口

  • 删除 PollingRealnameHandlerCardCategoryIndustry 跳过实名的判断。
  • 修正 pkg/constants/iot.go 中“普通卡必需实名、行业卡无需实名”的绝对化注释和依赖逻辑。
  • PollingRealnameHandlerPollingCarddataHandlerPollingCardStatusHandler 只调用 Application 用例,不再直接更新卡或执行业务联动。
  • 删除重复流量增量算法,只保留领域实现。
  • RefreshCardDataFromGateway 改为调用 RequestCardObservation + ApplyCardObservation
  • ManualUpdateRealnameStatus 改为调用领域用例。
  • 获取实名链接后的 ManualTriggerService.TriggerSingle 改为 CreateSyncTriggerSeries
  • C 端和后台设备操作中直接调用 Gateway 的路径迁入 Application再在用例成功边界创建触发序列。

10.2 保留并复用

  • Gateway Client 的加密、签名和 HTTP 封装。
  • Redis 分片 Sorted Set 调度基础设施。
  • Asynq Worker。
  • 卡流量同步锁,迁移为通用请求互斥实现。
  • 现有资产手动刷新接口和权限契约。
  • 现有批量轮询运维能力;其执行逻辑和记录迁入新用例与统一审计后,再下线旧专用日志表。

10.3 数据变更

  • 不新增实名要求字段,继续以 tb_carrier.realname_link_type 判断是否需要实名及链接生成方式。
  • 发布前检查 iccid_19 重复数据并建立未删除数据范围内的唯一索引,保证 19 位回调精确命中。
  • 卡增加轮询活跃标记字段,或由独立调度状态表保存;实现阶段根据写入频率决定,不能把高频调度心跳写入核心卡表。
  • 现有 tb_polling_config 条件匹配迁移为单一全局活跃/不活跃策略,不再使用 card_condition/card_category 形成隐式轮询资格。
  • 事件任务载荷增加 scene/series_id/attempt/source/request_id/correlation_id/expected_state
  • 不创建 tb_card_sync_execution

十一、发布与人工验证

停机发布API 与 Worker 同时切换:

  1. 验证 realname_link_type=none/template/gateway 分别对应无需实名、模板实名和 Gateway 实名,不再按行业卡统一跳过。
  2. 验证 enable_polling=false 会移除自动轮询,但业务事件和手动刷新仍能按各自规则工作。
  3. 验证活跃卡使用活跃间隔,不活跃卡使用低频间隔,重新活跃后立即恢复。
  4. 验证一次业务事件形成立即、3 分钟、5 分钟三个任务。
  5. 验证停复机、实名和切卡达到预期状态后,剩余任务不再请求 Gateway。
  6. 验证同场景高频查询只合并重复序列,不压制新的停复机或支付事件。
  7. 验证单卡互斥只覆盖请求执行时间,不形成五分钟全局冷却。
  8. 验证 Gateway 超频时当前尝试直接记为 rate_limited,不创建退避状态,后续阶梯任务仍保留。
  9. 验证现有后台和 C 端刷新接口契约不变,且不额外创建阶梯序列。
  10. 验证移动、联通、电信回调均先经过防腐层19 位和 20 位 ICCID 分别按双列精确路由,重复成功回调不重复激活套餐。
  11. 验证解除实名回调只写 Integration Log不修改卡实名状态。
  12. 验证开放接口仍立即返回本地数据,事件触发失败不改变响应。
  13. 验证普通同步、状态变化、手动刷新和连续失败能够在审计中心按资源和触发序列查询。