hyapp-server/docs/幸运礼物重构第三步-链路接入与上线验收.md
2026-05-27 22:12:16 +08:00

6.9 KiB
Raw Blame History

幸运礼物重构第三步:链路接入与上线验收

本文档定义幸运礼物重构第三步。第三步把 v2 配置和 v2 抽奖引擎接回房间送礼主链路完成返奖、IM、后台审计、灰度上线和旧逻辑删除。当前不兼容旧代码切换完成后旧幸运礼物抽奖入口、旧规则表和旧模拟器都应下线。

目标

目标 说明
主链路接入 room-service 扣费后调用 v2 抽奖
返奖一致 activity_outboxwallet-service 入账,钱包 outbox 通知余额
房间表现一致 lucky_gift_drawn IM 和区域播报由 outbox 补偿
后台可审计 后台能查 draw、候选表、控制模式、RTP、奖池和风控快照
可灰度回滚 pool_id/room_id/region 控制 v2 开关
删除旧逻辑 验收完成后移除旧 v1 抽奖和旧配置入口

主链路

Client
  -> gateway POST /api/v1/rooms/gift/send
  -> room-service 校验房间和目标
  -> wallet-service DebitGift
  -> room-service 调 activity-service ExecuteLuckyGiftDrawV2
  -> activity-service 本地事务写 draw + outbox
  -> room-service 落 Room Cell 礼物、热度、榜单
  -> gateway 返回 lucky_gift
  -> activity worker 返奖入账
  -> activity worker 投递 lucky_gift_drawn IM
  -> wallet/notice 投递 WalletBalanceChanged

接口要求

App 送礼请求

幸运礼物必须传明确 pool_id

{
  "room_id": "room_1",
  "command_id": "cmd_001",
  "target_type": "user",
  "target_user_ids": [10002],
  "gift_id": "lucky_star_100",
  "gift_count": 1,
  "pool_id": "lucky_100"
}

不再支持“礼物类型是 lucky 但不传 pool_id 时走 default”的隐式路径。

送礼响应

{
  "lucky_gift": {
    "enabled": true,
    "draw_id": "lucky_draw_xxx",
    "command_id": "cmd_001",
    "pool_id": "lucky_100",
    "rule_version": 12,
    "stage": "normal",
    "control_mode": "normal",
    "selected_tier_id": "normal_0_5x",
    "multiplier_ppm": 500000,
    "base_reward_coins": 50,
    "activity_subsidy_coins": 0,
    "effective_reward_coins": 50,
    "reward_status": "pending",
    "created_at_ms": 1779259000000
  }
}

客户端规则:

场景 处理
reward_status=pending 展示中奖结果和“奖励处理中”,不本地加余额
收到 WalletBalanceChanged 更新余额
收到同一 draw_id 的 IM 去重,不重复播放
lucky_gift 为空 按普通礼物处理

outbox 要求

抽奖事务只写事实和 outbox

outbox 作用
LuckyGiftRewardCredit 调钱包返奖
LuckyGiftDrawnRoomIM 投递房间开奖结果
LuckyGiftBigWinBroadcast 投递区域或全站播报

顺序要求:

  1. 先返奖入账。
  2. 再投递房间开奖结果。
  3. 最后标记 draw 为 granted

如果返奖已成功但 IM 失败:

状态 处理
draw 不能标记 failed,避免覆盖账务事实
outbox 继续重试 IM
后台 展示“返奖成功,表现补偿中”

后台审计

后台必须支持:

页面 能力
抽奖列表 pool_id/user_id/room_id/status/control_mode 查询
抽奖详情 展示候选表、过滤原因、权重、随机落点
RTP 看板 展示目标 RTP、实际 RTP、控制模式分布
奖池看板 展示 platform / room / gift 水位
风控看板 展示用户、设备、房间、主播过滤次数
outbox 看板 展示 pending/retryable/failed

抽奖详情必须能回答:

为什么这次是 0x
为什么 100x 被过滤?
为什么进入 boost/cooldown
这次随机落点在哪里?
返奖是否到账?
房间 IM 是否投递?

灰度策略

阶段 范围 要求
shadow 只计算 v2不返奖、不发 IM 和模拟结果接近
internal 内部房间、小额礼物 outbox 和钱包稳定
room whitelist 白名单房间 用户体验指标正常
region canary 单区域小流量 RTP 和投诉稳定
full 全量开放 旧逻辑可删除

灰度开关:

开关 作用
lucky_gift_v2_enabled 全局 v2 开关
pool_v2_enabled 单奖池开关
room_whitelist 房间白名单
region_whitelist 区域白名单
disable_high_tier 临时关闭高倍
reward_credit_enabled 钱包事故时暂停返奖 dispatchdraw 保持 pending

监控指标

指标 告警
base_rtp 超出目标波动带
effective_rtp 高于预算预期
zero_rate 高于配置预期
zero_streak_p95 超过体验阈值
control_mode_boost_ratio 长期过高说明概率或奖池不健康
control_mode_cooldown_ratio 长期过高说明派奖过多
pool_balance_min 接近 reserve
risk_filter_count 过高说明风控在替代概率控制
outbox_pending_count 堆积
reward_credit_latency 到账延迟
draw_error_count 抽奖事务失败

旧逻辑删除

全量稳定后删除:

旧内容 删除条件
lucky_gift_rules 写入口 v2 后台发布稳定
multiplier_ppms -> tiers(weight=0) 归一化 v2 引擎全量
selectLuckyCandidate 自动权重模型 v2 引擎全量
tools/lucky-gift-v2-demo 写死倍率模拟 新模拟器覆盖
pool_id 默认奖池路径 App 全部传明确 pool_id

实施任务

  1. 增加 ExecuteLuckyGiftDrawV2 内部接口。
  2. room-service 送礼链路改调 v2。
  3. gateway 响应增加 stage/control_mode
  4. activity outbox 拆分返奖、房间 IM、区域播报事件。
  5. 后台增加抽奖详情和候选表审计。
  6. 增加灰度开关和监控指标。
  7. shadow draw 跑满一个结算窗口。
  8. 灰度切流。
  9. 全量后删除旧逻辑。

验收标准

验收项 标准
App 参数 幸运礼物不传 pool_id 必须拒绝,不走 default
扣费顺序 钱包扣费成功后才调用 v2 抽奖
事务边界 抽奖事务内不调用钱包返奖或 IM
同步响应 lucky_gift 返回 stage/control_mode/multiplier_ppm/reward_status
余额一致 客户端余额只由 WalletBalanceChanged 或余额查询更新
outbox 幂等 重试不会重复返奖、重复 IM 可由 event_id/draw_id 去重
后台审计 任一 draw 可查看完整候选表和过滤原因
shadow 验证 shadow 结果的 RTP、命中率、连续 0 分布与模拟报告一致
灰度指标 灰度期间 base RTP 在控制带内outbox 无持续堆积
体验指标 100 金币礼物 zero_streak_p95 不超过配置阈值
删除旧逻辑 全量稳定后旧配置入口、旧抽奖引擎、旧默认奖池路径已删除
全量测试 make test 通过

第三步完成后,幸运礼物 v2 才算真正上线。前两步只完成规则和引擎,不能直接对外开放。