修复多人游戏排行榜问题

This commit is contained in:
咕谷酱
2025-08-22 13:52:28 +08:00
parent 6136b9fed3
commit b300ce9b09
13 changed files with 1008 additions and 324 deletions

View File

@@ -11,14 +11,13 @@ from app.router.v2.stats import (
)
async def cleanup_stale_online_users() -> tuple[int, int, int]:
"""清理过期的在线和游玩用户,返回清理的用户数(online_cleaned, playing_cleaned, metadata_cleaned)"""
async def cleanup_stale_online_users() -> tuple[int, int]:
"""清理过期的在线和游玩用户,返回清理的用户数"""
redis_sync = get_redis_message()
redis_async = get_redis()
online_cleaned = 0
playing_cleaned = 0
metadata_cleaned = 0
try:
# 获取所有在线用户
@@ -72,63 +71,10 @@ async def cleanup_stale_online_users() -> tuple[int, int, int]:
playing_cleaned = len(stale_playing_users)
logger.info(f"Cleaned {playing_cleaned} stale playing users")
# 新增清理过期的metadata在线标记
# 这个步骤用于清理那些由于异常断开连接而没有被正常清理的metadata键
metadata_cleaned = 0
try:
# 查找所有metadata:online:*键
metadata_keys = []
cursor = 0
pattern = "metadata:online:*"
# 使用SCAN命令遍历所有匹配的键
while True:
cursor, keys = await redis_async.scan(cursor=cursor, match=pattern, count=100)
metadata_keys.extend(keys)
if cursor == 0:
break
# 检查这些键是否对应有效的在线用户
orphaned_metadata_keys = []
for key in metadata_keys:
if isinstance(key, bytes):
key_str = key.decode()
else:
key_str = key
# 从键名中提取用户ID
user_id = key_str.replace("metadata:online:", "")
# 检查用户是否在在线用户集合中
is_in_online_set = await _redis_exec(redis_sync.sismember, REDIS_ONLINE_USERS_KEY, user_id)
is_in_playing_set = await _redis_exec(redis_sync.sismember, REDIS_PLAYING_USERS_KEY, user_id)
# 如果用户既不在在线集合也不在游玩集合中检查TTL
if not is_in_online_set and not is_in_playing_set:
# 检查键的TTL
ttl = await redis_async.ttl(key_str)
# TTL < 0 表示键没有过期时间或已过期
# 我们只清理那些明确过期或没有设置TTL的键
if ttl < 0:
# 再次确认键确实存在且没有对应的活跃连接
key_value = await redis_async.get(key_str)
if key_value:
# 键存在但用户不在任何集合中且没有有效TTL可以安全删除
orphaned_metadata_keys.append(key_str)
# 清理孤立的metadata键
if orphaned_metadata_keys:
await redis_async.delete(*orphaned_metadata_keys)
metadata_cleaned = len(orphaned_metadata_keys)
logger.info(f"Cleaned {metadata_cleaned} orphaned metadata:online keys")
except Exception as e:
logger.error(f"Error cleaning orphaned metadata keys: {e}")
except Exception as e:
logger.error(f"Error cleaning stale users: {e}")
return online_cleaned, playing_cleaned, metadata_cleaned
return online_cleaned, playing_cleaned
async def refresh_redis_key_expiry() -> None: