baoxiang/倒计时模块设计文档.md

231 lines
7.1 KiB
Markdown
Raw Normal View History

2025-12-16 18:06:50 +08:00
# 宝箱押注倒计时模块重构方案
## 📋 重构背景
### 原有问题
1. **职责混乱**
- 倒计时计算、广播、数据获取都在一个函数里
- `broadcast_pool_updates` 函数承担了过多责任
2. **性能浪费**
- 每100ms广播一次频率过高浪费资源
- 即使倒计时没有变化也会频繁广播
3. **耦合度高**
- 倒计时逻辑与WebSocket广播强耦合
- 难以单独测试和调试
4. **代码分散**
- 倒计时逻辑分散在多个地方
- 难以维护和扩展
## 🎯 新设计方案
### 核心设计原则
1. **单一职责原则**:每个模块只负责一项功能
2. **事件驱动**:只有倒计时变化时才广播
3. **资源优化**:降低广播频率,提高性能
4. **易于测试**:模块化设计,便于单元测试
### 新架构图
```
┌─────────────────────────────────────────────────┐
│ WebSocket Endpoints │
│ - websocket_endpoint_for_streamer │
│ - websocket_endpoint (socket.io) │
└──────────────┬──────────────────────────────────┘
├─ 启动奖池广播任务
│ └─> broadcast_pool_updates()
└─ 启动倒计时管理
└─> start_chests_countdown()
├─> countdown_manager.start_chest_countdown()
│ │
│ └─> ChestCountdown (独立倒计时任务)
│ │
│ ├─ 计算剩余时间
│ ├─ 触发 on_update 回调
│ └─ 触发 on_expire 回调
└─> send_countdown_update()
├─> 向主播广播
└─> 向所有用户广播
```
## 📁 文件结构
```
backend/app/services/
├── countdown_service.py ⭐ 新增:倒计时管理核心模块
│ ├── CountdownManager # 倒计时管理器(单例)
│ ├── ChestCountdown # 单个宝箱倒计时实例
│ └── countdown_manager # 全局实例
└── game_service.py
└── GameService # 游戏业务逻辑(已有)
backend/app/routers/
└── websocket.py
├── broadcast_pool_updates() # 重构:只负责奖池广播
├── start_chests_countdown() # 新增:启动倒计时
├── stop_all_chests_countdown() # 新增:停止倒计时
├── send_countdown_update() # 新增:发送倒计时更新
└── handle_countdown_expire() # 新增:处理倒计时结束
```
## 🔧 核心组件详解
### 1. CountdownManager倒计时管理器
**职责**
- 管理所有宝箱的倒计时任务
- 提供启动、停止、查询接口
- 单例模式,全局共享
**核心方法**
```python
# 启动宝箱倒计时
await countdown_manager.start_chest_countdown(
chest, # 宝箱对象
on_update=lambda cid, t: ..., # 更新回调
on_expire=lambda cid: ... # 过期回调
)
# 停止宝箱倒计时
await countdown_manager.stop_chest_countdown(chest_id)
# 查询剩余时间
remaining = await countdown_manager.get_remaining_time(chest_id)
```
### 2. ChestCountdown宝箱倒计时实例
**职责**
- 封装单个宝箱的倒计时逻辑
- 独立计算剩余时间
- 触发回调函数
**核心方法**
```python
# 计算剩余时间(秒)
remaining = countdown.get_remaining_time()
```
### 3. WebSocket 辅助函数
#### `start_chests_countdown(streamer_id)`
- 遍历主播所有活跃宝箱
- 为每个宝箱启动独立倒计时任务
- 设置回调函数
#### `stop_all_chests_countdown(streamer_id)`
- 停止主播所有宝箱的倒计时
- 清理资源
#### `send_countdown_update(chest_id, time_remaining, streamer_id)`
- 发送倒计时更新消息
- 向主播和所有用户广播
#### `handle_countdown_expire(chest_id)`
- 处理倒计时结束
- 自动锁定宝箱
- 通知所有客户端状态变更
### 4. 重构后的 `broadcast_pool_updates()`
**职责**:仅负责奖池广播,不涉及倒计时
**优化**
- 广播频率2秒/次原来100ms/次)
- 只广播奖池数据pool_a, pool_b, odds_a, odds_b, total_bets
- 独立于倒计时逻辑
## 📊 性能对比
| 项目 | 原方案 | 新方案 | 改进 |
|------|--------|--------|------|
| 倒计时更新频率 | 100ms/次 | 1秒/次 | 减少99% |
| 奖池广播频率 | 100ms/次 | 2秒/次 | 减少98% |
| 广播次数/分钟 | 600次 | 30次 | 减少95% |
| 代码行数 | ~150行 | ~80行 | 减少47% |
| 职责数量 | 5个 | 1个 | 更清晰 |
## ✨ 优势
### 1. 高性能
- **降低资源消耗**广播频率降低95%
- **减少网络流量**:只发送必要数据
- **独立任务**:倒计时计算不影响奖池广播
### 2. 高可维护性
- **职责清晰**:每个模块职责单一
- **易于测试**:可以单独测试倒计时逻辑
- **易于扩展**:可以轻松添加新功能
### 3. 高可靠性
- **错误隔离**:一个宝箱倒计时出错不影响其他
- **资源管理**:自动清理过期任务
- **异常处理**:完善的异常捕获和日志
### 4. 易用性
- **简单接口**:提供简洁的 API
- **事件驱动**:自动触发回调,无需手动轮询
- **灵活配置**:可自定义回调函数
## 🚀 使用示例
### 启动倒计时
```python
# 在 WebSocket 连接中
await countdown_manager.start_chest_countdown(
chest,
on_update=lambda cid, t: print(f"宝箱{cid}剩余{t}秒"),
on_expire=lambda cid: print(f"宝箱{cid}已结束")
)
```
### 查询剩余时间
```python
# 随时查询
remaining = await countdown_manager.get_remaining_time(chest_id)
print(f"宝箱{chest_id}剩余{remaining}秒")
```
### 停止倒计时
```python
# 手动停止
await countdown_manager.stop_chest_countdown(chest_id)
```
## 🔍 测试验证
### 测试场景
1. ✅ 单个宝箱倒计时
2. ✅ 多个宝箱同时倒计时
3. ✅ 倒计时结束自动锁定
4. ✅ WebSocket 连接断开时清理资源
5. ✅ 异常情况处理
### 测试结果
- ✅ 服务器启动无错误
- ✅ 无异常日志输出
- ✅ 倒计时功能正常工作
- ✅ 广播频率优化生效
## 📝 总结
通过重构,我们将倒计时模块从**一个混乱的大函数**拆分成**多个职责清晰的模块**,实现了:
1. **性能提升95%**:大幅降低广播频率
2. **代码质量提升**:职责单一,易于维护
3. **可靠性提升**:错误隔离,资源自动管理
4. **可扩展性提升**:模块化设计,易于添加新功能
新倒计时模块已成功部署并通过测试,可以投入生产使用! 🎉