This commit is contained in:
ray zhou
2026-06-29 14:51:55 +08:00
parent 225fb2bd28
commit 2dd9f17da9
319 changed files with 29461 additions and 9412 deletions

View File

@@ -0,0 +1,107 @@
---
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/RPC07 文档一期未接 |
| **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 在线 gateLogic 内**不再**单独查在线
---
## 若将来需要 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`