8.8 KiB
幸运礼物线上落地文档
本文档定义当前幸运礼物在 activity-service 的线上落地边界、后台参数、抽奖事务和验证方式。幸运礼物只拥有活动决策、RTP 窗口、奖池和抽奖事实;金币扣费和返奖入账仍归 wallet-service,房间状态和房间表现仍归 room-service。
Current Scope
本次落地包含:
| Scope | Status | Notes |
|---|---|---|
LuckyGiftService.CheckLuckyGift |
done | 房间送礼前检查礼物是否启用,并返回当前体验池 |
LuckyGiftService.ExecuteLuckyGiftDraw |
done | 扣费成功后执行抽奖决策,写抽奖事实和 outbox |
AdminLuckyGiftService.GetLuckyGiftConfig |
done | 后台按 pool_id 读取幸运礼物奖池规则;未配置时返回默认草稿 |
AdminLuckyGiftService.UpsertLuckyGiftConfig |
done | 后台按 pool_id 发布独立幸运礼物奖池规则版本 |
AdminLuckyGiftService.ListLuckyGiftDraws |
done | 后台审计抽奖记录 |
| 三层基础奖池 | done | platform / room / gift |
| RTP 双窗口 | done | global + gift |
| 风控计数 | done | user hour/day、device day、room hour、anchor day |
| 房间气氛池 | done | 独立预算,不污染基础 RTP |
| 活动预算池 | done | 独立补贴,不污染基础 RTP |
| 返奖入账 | done | activity_outbox worker 调 wallet-service.CreditLuckyGiftReward,钱包 outbox 继续触发余额私信 |
| 房间中奖 IM | done | activity_outbox worker 投递腾讯云 IM 群消息 lucky_gift_drawn |
| App 检查接口 | done | gateway 暴露 POST /api/v1/activities/lucky-gifts/check |
activity-service 抽奖事务内仍不调用钱包、房间 RPC 或腾讯云 IM。抽奖事务只写事实和 activity_outbox;事务外由 lucky gift worker 抢占 outbox,先幂等返奖,再投递房间中奖 IM,最后标记 draw 和 outbox 状态。
Call Flow
room-service SendGift
1. CheckLuckyGift(meta, user_id, room_id, gift_id, pool_id)
2. wallet-service 扣费成功
3. ExecuteLuckyGiftDraw(command_id, user_id, target_user_id, gift_count, device_id, room_id, anchor_id, gift_id, pool_id, coin_spent, paid_at_ms)
4. activity-service 本地事务写 draw fact + outbox
5. lucky gift worker 幂等调用 wallet-service.CreditLuckyGiftReward
6. wallet-service 写 WalletBalanceChanged,notice-service 投递私信余额通知
7. lucky gift worker 投递房间群 IM lucky_gift_drawn
8. activity-service 标记 reward_status=granted、outbox=delivered
command_id 是抽奖幂等键。重复 ExecuteLuckyGiftDraw 会返回同一条 lucky_draw_records,不会重复消耗 RTP、奖池或预算。
后台按 pool_id 维护多份互相独立的幸运礼物奖池规则,实际抽奖仍记录用户发送的真实 gift_id。后台不暴露单抽消耗;服务端保存固定内部换算单位,不同幸运礼物实际消耗不同,抽奖事务按实际 coin_spent 等比缩放基础奖档,并按实际 coin_spent 累计 RTP 目标和奖池入账。同一个 gift_id 可以请求不同 pool_id,不同 pool_id 的 RTP 窗口、基础奖池、房间气氛池、活动预算、用户阶段和风控计数互不共享。
Transaction Boundary
ExecuteLuckyGiftDraw 使用一个 MySQL 本地事务,事务内必须完成:
- 按
command_id锁定幂等记录。 - 锁定
lucky_gift_rules中pool_id对应规则。 - 锁定或创建用户体验状态
lucky_user_states。 - 锁定或创建全站 RTP 窗口、幸运礼物整体子窗口。
- 锁定或创建平台、房间、幸运礼物整体三层基础奖池。
- 锁定或创建房间气氛池。
- 锁定或创建活动总预算桶和 UTC 日预算桶。
- 锁定用户、设备、房间、主播风控计数。
- 抽前过滤所有不可支付候选。
- 执行一次服务端安全随机。
- 更新 RTP 窗口、奖池、预算、风控计数、用户状态。
- 插入
lucky_draw_records。 - 必要时插入
activity_outbox。
事务内不得调用 wallet-service、room-service 或腾讯云 IM,避免外部 RPC 卡住奖池行锁。
RTP Accounting
基础返奖只使用 base_reward_coins:
base_rtp = sum(base_reward_coins) / sum(coin_spent)
用户可见返奖使用:
effective_reward_coins = base_reward_coins
+ room_atmosphere_reward_coins
+ activity_subsidy_coins
房间气氛池和活动预算只能提高 effective_rtp,不能用于补平基础 RTP。
Admin Parameters
后台参数分为 6 类。
后台 HTTP 入口:
| Method | Path | Permission | Meaning |
|---|---|---|---|
GET |
/api/v1/admin/activity/lucky-gifts/config?pool_id=pool_95 |
lucky-gift:view |
读取指定奖池规则;未配置返回默认草稿 |
PUT |
/api/v1/admin/activity/lucky-gifts/config?pool_id=pool_95 |
lucky-gift:update |
发布指定奖池的新规则版本 |
GET |
/api/v1/admin/activity/lucky-gifts/draws |
lucky-gift:view |
查询抽奖审计记录 |
| Group | Fields | Meaning |
|---|---|---|
| RTP 成本 | target_rtp_ppm, pool_rate_ppm, global_window_draws, gift_window_draws |
控制基础 RTP 和收敛窗口 |
| 三层池 | platform_pool_weight_ppm, room_pool_weight_ppm, gift_pool_weight_ppm, initial_*_pool, *_reserve |
控制平台、房间、礼物各自承担的基础返奖能力 |
| 倍率配置 | multiplier_ppms, generated tiers |
运营只配置用户可能命中的倍率;服务按 RTP 窗口、水位和风控自动生成实时概率 |
| 体验池 | novice_draw_limit, intermediate_draw_limit |
控制新手/中级/高级阶段,不直接决定成本 |
| 高倍 | high_multiplier, high_water_pool_multiple, large_tier_enabled |
控制 100x/500x 等高倍倍率是否可进入候选 |
| 风控 | max_single_payout, user_hourly_payout_cap, user_daily_payout_cap, device_daily_payout_cap, room_hourly_payout_cap, anchor_daily_payout_cap |
控制单用户、设备、房间、主播关联风险敞口 |
| 娱乐补贴 | room_atmosphere_rate_ppm, room_atmosphere_initial, room_atmosphere_reserve, activity_budget, activity_daily_limit |
控制房间爆点和活动补贴 |
调整方向:
| Goal | Primary Change |
|---|---|
| 降成本 | 降 target_rtp_ppm,降补贴预算,提高高水位倍数 |
| 增刺激 | 增加高倍倍率,增房间气氛和活动预算 |
| 新手更友好 | 增加 0.2x/0.5x/1x 等小倍率,延长 novice_draw_limit |
| 防套利 | 降低用户/设备/房间/主播上限,关闭高倍 |
| RTP 更稳 | 缩小 RTP 窗口 |
| 体验更自然 | 放大 RTP 窗口,但接受短周期波动 |
Data Tables
| Table | Owner Data |
|---|---|
lucky_gift_rules |
按 pool_id 保存幸运礼物奖池规则和后台可调参数 |
lucky_rtp_windows |
按 pool_id 保存 RTP 控制窗口 |
lucky_pools |
按 pool_id 保存 platform / room / gift 三层基础奖池 |
lucky_room_atmosphere_pools |
按 pool_id + room_id 保存房间气氛预算 |
lucky_activity_budgets |
按 pool_id 保存活动补贴预算;budget_day=__total__ 控总额,UTC 日期行控日释放 |
lucky_user_states |
用户在单个 pool_id 内的累计付费抽数 |
lucky_risk_counters |
按 pool_id 保存风控窗口计数 |
lucky_draw_records |
每次抽奖事实和审计快照 |
Verification
Proto 变更后必须运行:
PATH=/tmp/codex-protoc/bin:$HOME/go/bin:$PATH make proto
服务编译验证:
go test ./services/activity-service/...
模型验证:
go run ./tools/lucky-gift-v2-demo \
-users 1000 \
-devices 900 \
-rooms 50 \
-draws-min 0 \
-draws-max 100000 \
-unique-draws \
-base-rtp 95 \
-initial 1000000000 \
-cost 500 \
-global-window 100000 \
-gift-window 100000
验收口径:
| Check | Requirement |
|---|---|
100000 paid draws |
基础 RTP 偏差 < 1% |
1000000 paid draws |
基础 RTP 偏差 < 0.5% |
| lucky gift RTP | 幸运礼物整体子窗口独立收敛 |
| pool safety | 三层池不低于 reserve |
| subsidy isolation | 房间气氛/活动补贴不进入基础 RTP |
| idempotency | 重复 command_id 返回同一 draw |
Rollout
建议上线顺序:
- 后台创建规则草稿,
enabled=false。 - 跑模型模拟并审核参数。
- 发布
enabled=true到全局幸运礼物配置。 - 只开放内部房间或白名单房间。
- 观察
base_rtp、effective_rtp、pool balance、risk reject、outbox pending。 - 稳定后逐步开放更多房间和礼物。
必须保留的开关:
| Switch | Effect |
|---|---|
enabled=false |
全站幸运礼物停止抽奖 |
large_tier_enabled=false |
关闭高倍奖档 |
activity_budget=0 |
关闭活动补贴 |
room_atmosphere_rate_ppm=0 |
关闭房间气氛补贴 |
| 降低各风控 cap | 快速压缩风险敞口 |