hyapp-server/docs/语音房火箭功能架构.md
2026-06-09 19:16:05 +08:00

130 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 语音房火箭功能架构
## 服务边界
- `room-service` 是火箭进度、点火、待发射队列和奖励结算 owner。
- `gateway-service` 只提供 App HTTP 入口和鉴权后的协议转换;`GET /api/v1/rooms/{room_id}/rocket` 会按奖励 `resource_group_id` 查询 wallet-service 并嵌入 `resource_group.items`
- `server/admin` 只读写 `room-service` 内部配置接口,不直连 room 数据库。
- `wallet-service` 负责资源组发放。
- `activity-service` 负责区域/全局飘屏和带用户资料的奖励房间 IM。
- 腾讯云 IM 负责房间群、区域群和全局群投递。
## 状态模型
`RoomRocketState` 保存当前正在累计的火箭和已点火待发射队列。
| 字段 | 说明 |
| --- | --- |
| `current_level` | 当前正在累计的等级,最高 5 |
| `current_fuel` | 当前等级燃料 |
| `fuel_threshold` | 当前等级阈值 |
| `status` | `charging``completed` |
| `rocket_id` | 当前正在累计的火箭 ID |
| `pending_launches` | 已点火、等待延迟发射的火箭 |
| `last_rewards` | 最近一次发射奖励结果 |
`pending_launches` 中每一项锁定:
| 字段 | 说明 |
| --- | --- |
| `rocket_id` | 本枚火箭幂等 ID |
| `level` | 点火等级 |
| `fuel_threshold` | 点火阈值 |
| `ignited_at_ms` | 点火时间 |
| `launch_at_ms` | 预计发射时间 |
| `reset_at_ms` | UTC 日重置时间 |
| `top1_user_id` | 点火时贡献第一 |
| `igniter_user_id` | 点火人 |
| `config_version` | 点火配置版本 |
| `cover_url` | 小封面图 |
## 送礼加燃料
1. `SendGift` 先调用 wallet 扣费。
2. 扣费成功后Room Cell 串行更新热度、礼物榜和火箭。
3. 燃料来自 wallet 返回的 `heat_value`
4. 当前等级未满时,增加 `min(本次燃料, 剩余阈值)`
5. 超过阈值的燃料直接写入 `overflow_fuel`,不进入下一等级。
6. 当前等级满后:
- 写入 `RoomRocketFuelChanged`
- 写入 `RoomRocketIgnited`
- 将当前火箭追加到 `pending_launches`
- 如果未到 5 级,立刻把当前状态切到下一等级,`current_fuel=0`
- 如果 5 级已满,状态切到 `completed`UTC 重置前不再累计新火箭。
## 发射结算
1. `RoomRocketIgnited` 被 outbox worker 处理后,安排 RocketMQ delayed wakeup。
2. 本地扫描 worker 也会扫描已加载且仍持有 lease 的 Room Cell作为兜底。
3. 到点后 `LaunchRoomRocket` 命令重新加载 Room Cell。
4. 命令必须校验:
- `rocket_id` 存在于 `pending_launches`
- `level` 匹配。
- `launch_at_ms <= now_ms`
- `now_ms < reset_at_ms`
5. 结算时按发射瞬间 `OnlineUsers` 抽在房奖励。
6. `top1``igniter` 使用点火时锁定的用户,离房后仍发对应奖励。
7. 发奖完成后移除该 `pending_launches` 项,当前正在累计的火箭不被发射命令推进。
## 奖励
| 奖励 | 用户来源 |
| --- | --- |
| 点火人奖励 | `pending_launches[].igniter_user_id` |
| 贡献第一奖励 | `pending_launches[].top1_user_id` |
| 在房奖励 | 发射命令执行时 Room Cell `OnlineUsers` |
发放规则:
| 奖励 | 规则 |
| --- | --- |
| 在房奖励 | 每个在线用户从 `inRoomRewards` 按权重随机抽 1 个 |
| 贡献第一奖励 | top1 用户获得 `top1Rewards` 配置池内全部奖励 |
| 点火人奖励 | 点火用户获得 `igniterRewards` 配置池内全部奖励 |
同一用户同时是 top1 和点火人时top1 池和点火人池继续叠加;如果该用户发射瞬间仍在房间,也会再拿 1 个在房随机奖励。
## IM
| 事实 | IM | 投递方 |
| --- | --- | --- |
| `RoomRocketFuelChanged` | `room_rocket_fuel_changed` | room-service IM bridge |
| `RoomRocketIgnited` | `room_rocket_ignited` | room-service IM bridge |
| `RoomRocketIgnited` | `room_rocket` 区域/全局飘屏 | activity-service |
| `RoomRocketLaunched` | `room_rocket_launched` | room-service IM bridge |
| `RoomRocketRewardGranted` | `room_rocket_reward_granted` 房间奖励 IM | activity-service |
奖励 IM 由 activity-service 查询用户公开资料后组装,包含头像、昵称、短 ID 和奖励信息。room-service 不反查 user-service。
奖励资源组内容不写入 Room Cell客户端需要金币数量、有效期、聊天气泡或麦位特效素材时通过 rocket GET 接口读取展开后的 `resource_group`
## 高频处理
- Room Cell 串行处理送礼命令,所以同房高频送礼不会并发写乱进度。
- 满阈值时只把火箭追加到 `pending_launches`,不会阻塞下一等级继续累计。
- 房间状态 IM 通过 room outbox 补偿投递,不在送礼主链路同步调用腾讯 IM。
- 奖励 IM 合并为一条消息,`rewards` 内包含所有中奖人,避免按用户逐条堆积。
- RocketMQ delayed wakeup 只负责唤醒,最终发射仍由 Room Cell 命令校验。
## UTC 重置
- 火箭周期按 UTC 自然日。
- 到达 `reset_at_ms` 后,查询或下一次送礼会投影为 1 级新进度。
- 跨过 UTC 日界仍未发射的待发射火箭不结算。
## 后台配置
配置表:`room_rocket_configs`
| 字段 | 说明 |
| --- | --- |
| `enabled` | 是否开启 |
| `fuel_source` | 固定 `heat_value` |
| `launch_delay_ms` | 点火到发射延迟 |
| `broadcast_enabled` | 是否发飘屏 |
| `broadcast_scope` | `region``global``none` |
| `reward_stack_policy` | 历史兼容字段;当前特殊身份奖励按上方规则叠加 |
| `levels_json` | 5 级阈值、物料和奖励池 |
| `gift_fuel_rules_json` | 礼物燃料规则 |
`levels_json` 字段使用 `fuelThreshold``coverUrl``animationUrl``launchAnimationUrl``launchedImageUrl``inRoomRewards``top1Rewards``igniterRewards`