Files
cursor/plans/console_redis_在线推送_cf0daa26.plan.md
ray zhou 2dd9f17da9 ok
2026-06-29 14:51:55 +08:00

108 lines
4.9 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.

---
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`