108 lines
4.9 KiB
Markdown
108 lines
4.9 KiB
Markdown
---
|
||
name: Console Redis 在线推送
|
||
overview: 不建议在 slot_game 新增「用户是否在线」接口;邀请成功弹窗的在线判断应放在 slot_console,复用 EventBus 已维护的 Redis 在线集合,在 PendingPopupService 入队后「在线才 WS 即时推送、离线靠 HomeEvent 补弹」。
|
||
todos:
|
||
- id: user-online-service
|
||
content: 新增 UserOnlineService::isUserOnline(读 Redis getUserOnlineKey)+ 单测
|
||
status: completed
|
||
- id: pending-popup-online-gate
|
||
content: PendingPopupService::enqueue 在线才 notifyClientPOP,离线仅持久化
|
||
status: completed
|
||
- id: docs-verify-online
|
||
content: 更新 07 文档 enqueue 说明;跑 verify + 相关单测
|
||
status: in_progress
|
||
isProject: false
|
||
---
|
||
|
||
# 在线判断方案:不建议 slot_game,采用 slot_console Redis
|
||
|
||
## 结论(对你问题的直接回答)
|
||
|
||
**不建议在 [`slot_game`](slot_game) 新增控制器做在线判断。**
|
||
|
||
| 服务 | 职责 | 是否适合判断「大厅弹窗在线」 |
|
||
|------|------|------------------------------|
|
||
| **slot_game** | 游戏 WebSocket 网关(spin/bet/进游戏) | 否 — 用户在大厅连的是 **slot_hub**,不一定连 slot_game |
|
||
| **slot_hub** | 大厅 WS + `Gateway::isUidOnline($uid)`(见 [`BaseLogic`](slot_hub/plugin/slot/hub/logic/BaseLogic.php)) | 最准,但需跨服务 HTTP/RPC,07 文档一期未接 |
|
||
| **slot_console** | 弹窗入队、EventBus 维护 Redis 在线集合 | **合适** — 数据已有,无跨服务调用 |
|
||
|
||
当前邀请成功链路(已实现):
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Logic as LuckyRewardInviteLogic
|
||
participant Popup as PendingPopupService
|
||
participant Redis as Redis_online_set
|
||
participant WS as WsService_MQ
|
||
participant Home as HomeEvent
|
||
|
||
Logic->>Popup: enqueue 邀请人弹窗
|
||
Popup->>Popup: 写 user_pending_popup
|
||
Popup->>WS: notifyClientPOP(当前始终发送)
|
||
Note over Home: 离线/游戏中靠 home flush 补弹
|
||
```
|
||
|
||
你已选择 **slot_console + Redis** 方案:与 [07 待弹窗方案](docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md) 一致 — **持久化必做,WS 仅 best-effort**。
|
||
|
||
---
|
||
|
||
## 推荐实现(小改动,不改 slot_game)
|
||
|
||
### 1. 封装在线查询(slot_console)
|
||
|
||
在 [`RedisKeyManagerService`](slot_console/app/service/RedisKeyManagerService.php) 或新建 `UserOnlineService`(公共能力,非 Logic 型业务编排):
|
||
|
||
```php
|
||
public static function isUserOnline(int $uid): bool
|
||
{
|
||
if ($uid <= 0) {
|
||
return false;
|
||
}
|
||
return (bool) Redis::sIsMember(self::getUserOnlineKey(), (string) $uid);
|
||
}
|
||
```
|
||
|
||
数据来源:[`EventBus::websocketConnectEvent`](slot_console/app/command/EventBus.php) / `websocketUnconnectEvent` 已对 `getUserOnlineKey()` 做 `sAdd` / `sRem`。
|
||
|
||
**语义说明**:Redis 在线 = **有 WebSocket 连接**,不等于「一定在大厅」;游戏内是否弹仍由**客户端忽略 WS** + **HomeEvent 仅非 enter_game 时 flush** 保证(PRD 4.2)。
|
||
|
||
### 2. 调整 [`PendingPopupService::enqueue`](slot_console/app/service/PendingPopupService.php)
|
||
|
||
- **不变**:幂等写 `user_pending_popup`(离线也必须写,否则丢通知)
|
||
- **变更**:仅当 `isUserOnline($uid)` 为 true 时调用 `WsService::notifyClientPOP`
|
||
- 离线:跳过 WS,等 [`HomeEvent::appendLuckyRewardHomePopups`](slot_console/app/command/event/HomeEvent.php) 补弹
|
||
|
||
```php
|
||
if (UserOnlineService::isUserOnline($enqueueDto->uid)) {
|
||
WsService::notifyClientPOP(...);
|
||
}
|
||
```
|
||
|
||
此改动作用于**所有**走 `PendingPopupService` 的定向弹窗(含邀请成功 `lucky_reward_invite_success`),符合 F 通用机制。
|
||
|
||
### 3. 测试
|
||
|
||
- 单元测:`isUserOnline` 对 Redis mock 或集成测 sAdd/sIsMember
|
||
- 可选:集成测 invite_bind 成功后 pending 记录存在;在线/离线 WS 行为(若难 mock MQ,至少单测 PendingPopupService 分支)
|
||
|
||
### 4. 文档
|
||
|
||
- [07 用户定向弹窗通知机制方案](docs/requirements/lucky_rewards/07_用户定向弹窗通知机制方案.md) §4 `enqueue` 说明补一句:**即时 WS 仅在 Redis 在线集合命中时发送**
|
||
- [`LuckyRewardInviteLogic`](slot_console/app/api/logic/LuckyRewardInviteLogic.php) 的 `notifyInviterInviteSuccess` PHPDoc 注明依赖 PendingPopupService 在线 gate,Logic 内**不再**单独查在线
|
||
|
||
---
|
||
|
||
## 若将来需要 HTTP「查在线」给其他服务
|
||
|
||
- 优先 **slot_console `innerapi`**(如 `GET /innerapi/user/is-online?uid=`),读同一 Redis 集合
|
||
- 或 **slot_hub innerapi** 调 `Gateway::isUidOnline`(需 GatewayClient 配置,跨进程)
|
||
- **仍不建议 slot_game** — 除非明确要查「是否在游戏 WS 连接中」(与大厅弹窗无关)
|
||
|
||
---
|
||
|
||
## 不在本次范围
|
||
|
||
- slot_game 新 Controller
|
||
- slot_hub Gateway 跨服务封装(除非 Redis 与 Gateway 长期不一致再评估)
|
||
- 区分「大厅 vs 游戏中」的服务端精确状态(仍靠客户端 + HomeEvent `from`)
|