diff --git a/app/Console/Commands/AutoSaveExp.php b/app/Console/Commands/AutoSaveExp.php index 07fa3f5..258431f 100644 --- a/app/Console/Commands/AutoSaveExp.php +++ b/app/Console/Commands/AutoSaveExp.php @@ -87,32 +87,28 @@ class AutoSaveExp extends Command } /** - * 扫描 Redis,获取所有活跃房间及其在线用户列表。 + * 查询所有活跃房间及其在线用户列表。 + * + * 改为从数据库获取所有房间,再用 Redis::hkeys() 查询在线用户。 + * 这样可以避免 Redis SCAN + 前缀匹配不一致的问题, + * 且 Redis::hkeys() 会自动正确地加上前缀,与 ChatStateService::userJoin() 一致。 * * @return array> 格式:[房间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; }