Fix: 彻底抛弃Redis SCAN方案,改用Room::pluck+hkeys精准读取在线用户,解决predis前缀导致扫描失败的问题
This commit is contained in:
@@ -87,32 +87,28 @@ class AutoSaveExp extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描 Redis,获取所有活跃房间及其在线用户列表。
|
||||
* 查询所有活跃房间及其在线用户列表。
|
||||
*
|
||||
* 改为从数据库获取所有房间,再用 Redis::hkeys() 查询在线用户。
|
||||
* 这样可以避免 Redis SCAN + 前缀匹配不一致的问题,
|
||||
* 且 Redis::hkeys() 会自动正确地加上前缀,与 ChatStateService::userJoin() 一致。
|
||||
*
|
||||
* @return array<int, array<string>> 格式:[房间ID => [用户名, ...]]
|
||||
*/
|
||||
private function scanOnlineRooms(): array
|
||||
{
|
||||
$roomMap = [];
|
||||
$cursor = '0';
|
||||
|
||||
// 获取原始 Redis 客户端(不自动加前缀),用于直接操作完整 key 名
|
||||
$rawClient = Redis::connection()->client();
|
||||
// 从数据库取出所有房间 ID
|
||||
$roomIds = \App\Models\Room::pluck('id');
|
||||
|
||||
do {
|
||||
[$cursor, $keys] = Redis::scan($cursor, ['match' => '*room:*:users', 'count' => 100]);
|
||||
foreach ($keys ?? [] as $key) {
|
||||
// 从 key 中提取房间 ID,支持带前缀的格式(如 chatroom-database-room:1:users)
|
||||
if (preg_match('/room:(\d+):users/', $key, $m)) {
|
||||
$roomId = (int) $m[1];
|
||||
// 直接用原始客户端查找,避免 Laravel 自动加前缀导致 key 被拼接两次
|
||||
$usernames = $rawClient->hkeys($key);
|
||||
if (! empty($usernames)) {
|
||||
$roomMap[$roomId] = $usernames;
|
||||
}
|
||||
}
|
||||
foreach ($roomIds as $roomId) {
|
||||
// Laravel 的 Redis facade 会自动加配置的前缀,与 ChatStateService 存入时完全一致
|
||||
$usernames = Redis::hkeys("room:{$roomId}:users");
|
||||
if (! empty($usernames)) {
|
||||
$roomMap[(int) $roomId] = $usernames;
|
||||
}
|
||||
} while ($cursor !== '0');
|
||||
}
|
||||
|
||||
return $roomMap;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user