mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-28 16:20:56 +08:00
refactor: use CacheDict from CacheRoot instead of custom dict for memory cache
This commit is contained in:
@@ -5,10 +5,10 @@
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from typing import ClassVar
|
||||
|
||||
from zhenxun.services.cache import CacheRoot, cache_config
|
||||
from zhenxun.services.cache.cache_containers import CacheDict
|
||||
from zhenxun.services.cache.config import CacheMode
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.enum import CacheType
|
||||
@@ -22,6 +22,12 @@ LOG_COMMAND = "auth_snapshot"
|
||||
AUTH_SNAPSHOT_PREFIX = "AUTH_SNAPSHOT"
|
||||
PLUGIN_SNAPSHOT_PREFIX = "PLUGIN_SNAPSHOT"
|
||||
|
||||
# 内存缓存TTL配置
|
||||
AUTH_MEMORY_TTL = 10 # 权限快照内存缓存TTL(秒)
|
||||
AUTH_REDIS_TTL = 60 # 权限快照Redis缓存TTL(秒)
|
||||
PLUGIN_MEMORY_TTL = 30 # 插件快照内存缓存TTL(秒)
|
||||
PLUGIN_REDIS_TTL = 300 # 插件快照Redis缓存TTL(秒)
|
||||
|
||||
|
||||
class AuthSnapshotService:
|
||||
"""权限快照服务
|
||||
@@ -29,10 +35,8 @@ class AuthSnapshotService:
|
||||
提供权限快照的获取、缓存和失效管理
|
||||
"""
|
||||
|
||||
# 本地内存缓存(用于热点数据)
|
||||
_memory_cache: ClassVar[dict[str, tuple[float, AuthSnapshot]]] = {}
|
||||
_memory_cache_ttl: ClassVar[int] = 10 # 内存缓存TTL(秒)
|
||||
_cache_ttl: ClassVar[int] = 60 # Redis缓存TTL(秒)
|
||||
# 本地内存缓存(使用 CacheDict,自动处理过期)
|
||||
_memory_cache: ClassVar[CacheDict[AuthSnapshot] | None] = None
|
||||
|
||||
# 正在构建中的快照(防止并发重复构建)
|
||||
_building: ClassVar[dict[str, asyncio.Future]] = {}
|
||||
@@ -40,6 +44,17 @@ class AuthSnapshotService:
|
||||
# 构建锁(按 cache_key 粒度)
|
||||
_build_locks: ClassVar[dict[str, asyncio.Lock]] = {}
|
||||
|
||||
@classmethod
|
||||
def _get_memory_cache(cls) -> CacheDict[AuthSnapshot]:
|
||||
"""获取内存缓存实例(懒加载)"""
|
||||
if cls._memory_cache is None:
|
||||
cls._memory_cache = CacheRoot.cache_dict(
|
||||
f"{AUTH_SNAPSHOT_PREFIX}_MEMORY",
|
||||
expire=AUTH_MEMORY_TTL,
|
||||
value_type=AuthSnapshot,
|
||||
)
|
||||
return cls._memory_cache
|
||||
|
||||
@classmethod
|
||||
def _build_cache_key(cls, user_id: str, group_id: str | None, bot_id: str) -> str:
|
||||
"""构建缓存键"""
|
||||
@@ -69,9 +84,11 @@ class AuthSnapshotService:
|
||||
"""
|
||||
cache_key = cls._build_cache_key(user_id, group_id, bot_id)
|
||||
|
||||
memory_cache = cls._get_memory_cache()
|
||||
|
||||
# 1. 尝试从内存缓存获取
|
||||
if not force_refresh:
|
||||
if snapshot := cls._get_from_memory(cache_key):
|
||||
if snapshot := memory_cache.get(cache_key):
|
||||
return snapshot
|
||||
|
||||
# 2. 尝试从Redis获取
|
||||
@@ -80,9 +97,9 @@ class AuthSnapshotService:
|
||||
cached = await CacheRoot.get(CacheType.TEMP, cache_key)
|
||||
if cached and isinstance(cached, dict):
|
||||
snapshot = AuthSnapshot.model_validate(cached)
|
||||
if not snapshot.is_expired(cls._cache_ttl):
|
||||
if not snapshot.is_expired(AUTH_REDIS_TTL):
|
||||
# 更新内存缓存
|
||||
cls._set_to_memory(cache_key, snapshot)
|
||||
memory_cache.set(cache_key, snapshot)
|
||||
return snapshot
|
||||
except Exception as e:
|
||||
logger.debug(f"从Redis获取权限快照失败: {cache_key}", LOG_COMMAND, e=e)
|
||||
@@ -95,7 +112,7 @@ class AuthSnapshotService:
|
||||
# 4. 使用锁保护构建过程,防止并发重复构建
|
||||
async with lock:
|
||||
# 再次检查缓存(可能在等待锁的过程中已被其他协程构建)
|
||||
if snapshot := cls._get_from_memory(cache_key):
|
||||
if snapshot := memory_cache.get(cache_key):
|
||||
return snapshot
|
||||
|
||||
# 检查是否正在构建中(其他协程已开始构建)
|
||||
@@ -108,38 +125,6 @@ class AuthSnapshotService:
|
||||
# 5. 构建新快照
|
||||
return await cls._build_and_cache(user_id, group_id, bot_id, cache_key)
|
||||
|
||||
@classmethod
|
||||
def _get_from_memory(cls, cache_key: str) -> AuthSnapshot | None:
|
||||
"""从内存缓存获取"""
|
||||
if cache_key in cls._memory_cache:
|
||||
created_at, snapshot = cls._memory_cache[cache_key]
|
||||
if time.time() - created_at < cls._memory_cache_ttl:
|
||||
return snapshot
|
||||
# 过期,删除
|
||||
del cls._memory_cache[cache_key]
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _set_to_memory(cls, cache_key: str, snapshot: AuthSnapshot):
|
||||
"""设置内存缓存"""
|
||||
cls._memory_cache[cache_key] = (time.time(), snapshot)
|
||||
|
||||
# 清理过期的内存缓存(简单策略:超过1000条时清理)
|
||||
if len(cls._memory_cache) > 1000:
|
||||
cls._cleanup_memory_cache()
|
||||
|
||||
@classmethod
|
||||
def _cleanup_memory_cache(cls):
|
||||
"""清理过期的内存缓存"""
|
||||
now = time.time()
|
||||
expired_keys = [
|
||||
k
|
||||
for k, (created_at, _) in cls._memory_cache.items()
|
||||
if now - created_at > cls._memory_cache_ttl
|
||||
]
|
||||
for key in expired_keys:
|
||||
del cls._memory_cache[key]
|
||||
|
||||
@classmethod
|
||||
async def _build_and_cache(
|
||||
cls,
|
||||
@@ -166,7 +151,7 @@ class AuthSnapshotService:
|
||||
)
|
||||
|
||||
# 存入内存缓存
|
||||
cls._set_to_memory(cache_key, snapshot)
|
||||
cls._get_memory_cache().set(cache_key, snapshot)
|
||||
|
||||
future.set_result(snapshot)
|
||||
return snapshot
|
||||
@@ -185,7 +170,7 @@ class AuthSnapshotService:
|
||||
CacheType.TEMP,
|
||||
cache_key,
|
||||
snapshot.model_dump(),
|
||||
expire=cls._cache_ttl,
|
||||
expire=AUTH_REDIS_TTL,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug(f"缓存权限快照到Redis失败: {cache_key}", LOG_COMMAND, e=e)
|
||||
@@ -197,10 +182,11 @@ class AuthSnapshotService:
|
||||
参数:
|
||||
user_id: 用户ID
|
||||
"""
|
||||
# 清理内存缓存
|
||||
keys_to_delete = [k for k in cls._memory_cache if f":{user_id}:" in k]
|
||||
# 清理内存缓存(遍历 CacheDict 的 keys)
|
||||
memory_cache = cls._get_memory_cache()
|
||||
keys_to_delete = [k for k in memory_cache.keys() if f":{user_id}:" in k]
|
||||
for key in keys_to_delete:
|
||||
del cls._memory_cache[key]
|
||||
del memory_cache[key]
|
||||
|
||||
logger.debug(f"已失效用户 {user_id} 的权限快照缓存", LOG_COMMAND)
|
||||
|
||||
@@ -212,9 +198,10 @@ class AuthSnapshotService:
|
||||
group_id: 群组ID
|
||||
"""
|
||||
# 清理内存缓存
|
||||
keys_to_delete = [k for k in cls._memory_cache if f":{group_id}:" in k]
|
||||
memory_cache = cls._get_memory_cache()
|
||||
keys_to_delete = [k for k in memory_cache.keys() if f":{group_id}:" in k]
|
||||
for key in keys_to_delete:
|
||||
del cls._memory_cache[key]
|
||||
del memory_cache[key]
|
||||
|
||||
logger.debug(f"已失效群组 {group_id} 的权限快照缓存", LOG_COMMAND)
|
||||
|
||||
@@ -226,16 +213,18 @@ class AuthSnapshotService:
|
||||
bot_id: Bot ID
|
||||
"""
|
||||
# 清理内存缓存
|
||||
keys_to_delete = [k for k in cls._memory_cache if k.endswith(f":{bot_id}")]
|
||||
memory_cache = cls._get_memory_cache()
|
||||
keys_to_delete = [k for k in memory_cache.keys() if k.endswith(f":{bot_id}")]
|
||||
for key in keys_to_delete:
|
||||
del cls._memory_cache[key]
|
||||
del memory_cache[key]
|
||||
|
||||
logger.debug(f"已失效Bot {bot_id} 的权限快照缓存", LOG_COMMAND)
|
||||
|
||||
@classmethod
|
||||
def clear_all_cache(cls):
|
||||
"""清空所有缓存"""
|
||||
cls._memory_cache.clear()
|
||||
if cls._memory_cache:
|
||||
cls._memory_cache.clear()
|
||||
cls._build_locks.clear()
|
||||
logger.info("已清空所有权限快照缓存", LOG_COMMAND)
|
||||
|
||||
@@ -257,10 +246,8 @@ class PluginSnapshotService:
|
||||
提供插件信息的获取和缓存,支持本地内存缓存 + Redis 双层缓存
|
||||
"""
|
||||
|
||||
# 本地内存缓存
|
||||
_memory_cache: ClassVar[dict[str, tuple[float, PluginSnapshot]]] = {}
|
||||
_memory_cache_ttl: ClassVar[int] = 30 # 内存缓存TTL(秒)
|
||||
_cache_ttl: ClassVar[int] = 300 # Redis缓存TTL(秒)
|
||||
# 本地内存缓存(使用 CacheDict)
|
||||
_memory_cache: ClassVar[CacheDict[PluginSnapshot] | None] = None
|
||||
|
||||
# 正在构建中的快照
|
||||
_building: ClassVar[dict[str, asyncio.Future]] = {}
|
||||
@@ -268,6 +255,17 @@ class PluginSnapshotService:
|
||||
# 构建锁(按 cache_key 粒度)
|
||||
_build_locks: ClassVar[dict[str, asyncio.Lock]] = {}
|
||||
|
||||
@classmethod
|
||||
def _get_memory_cache(cls) -> CacheDict[PluginSnapshot]:
|
||||
"""获取内存缓存实例(懒加载)"""
|
||||
if cls._memory_cache is None:
|
||||
cls._memory_cache = CacheRoot.cache_dict(
|
||||
f"{PLUGIN_SNAPSHOT_PREFIX}_MEMORY",
|
||||
expire=PLUGIN_MEMORY_TTL,
|
||||
value_type=PluginSnapshot,
|
||||
)
|
||||
return cls._memory_cache
|
||||
|
||||
@classmethod
|
||||
def _build_cache_key(cls, module: str) -> str:
|
||||
"""构建缓存键"""
|
||||
@@ -287,10 +285,11 @@ class PluginSnapshotService:
|
||||
PluginSnapshot | None: 插件快照,不存在时返回None
|
||||
"""
|
||||
cache_key = cls._build_cache_key(module)
|
||||
memory_cache = cls._get_memory_cache()
|
||||
|
||||
# 1. 尝试从内存缓存获取(最快)
|
||||
if not force_refresh:
|
||||
if snapshot := cls._get_from_memory(cache_key):
|
||||
if snapshot := memory_cache.get(cache_key):
|
||||
return snapshot
|
||||
|
||||
# 2. 尝试从Redis获取
|
||||
@@ -299,8 +298,8 @@ class PluginSnapshotService:
|
||||
cached = await CacheRoot.get(CacheType.PLUGINS, cache_key)
|
||||
if cached and isinstance(cached, dict):
|
||||
snapshot = PluginSnapshot.model_validate(cached)
|
||||
if not snapshot.is_expired(cls._cache_ttl):
|
||||
cls._set_to_memory(cache_key, snapshot)
|
||||
if not snapshot.is_expired(PLUGIN_REDIS_TTL):
|
||||
memory_cache.set(cache_key, snapshot)
|
||||
return snapshot
|
||||
except Exception as e:
|
||||
logger.debug(f"从Redis获取插件快照失败: {module}", LOG_COMMAND, e=e)
|
||||
@@ -313,7 +312,7 @@ class PluginSnapshotService:
|
||||
# 4. 使用锁保护构建过程
|
||||
async with lock:
|
||||
# 再次检查缓存(可能在等待锁的过程中已被其他协程构建)
|
||||
if snapshot := cls._get_from_memory(cache_key):
|
||||
if snapshot := memory_cache.get(cache_key):
|
||||
return snapshot
|
||||
|
||||
# 检查是否正在构建中
|
||||
@@ -326,21 +325,6 @@ class PluginSnapshotService:
|
||||
# 5. 从数据库构建
|
||||
return await cls._build_and_cache(module, cache_key)
|
||||
|
||||
@classmethod
|
||||
def _get_from_memory(cls, cache_key: str) -> PluginSnapshot | None:
|
||||
"""从内存缓存获取"""
|
||||
if cache_key in cls._memory_cache:
|
||||
created_at, snapshot = cls._memory_cache[cache_key]
|
||||
if time.time() - created_at < cls._memory_cache_ttl:
|
||||
return snapshot
|
||||
del cls._memory_cache[cache_key]
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _set_to_memory(cls, cache_key: str, snapshot: PluginSnapshot):
|
||||
"""设置内存缓存"""
|
||||
cls._memory_cache[cache_key] = (time.time(), snapshot)
|
||||
|
||||
@classmethod
|
||||
async def _build_and_cache(
|
||||
cls, module: str, cache_key: str
|
||||
@@ -361,7 +345,7 @@ class PluginSnapshotService:
|
||||
)
|
||||
|
||||
# 存入内存缓存
|
||||
cls._set_to_memory(cache_key, snapshot)
|
||||
cls._get_memory_cache().set(cache_key, snapshot)
|
||||
|
||||
future.set_result(snapshot)
|
||||
return snapshot
|
||||
@@ -380,7 +364,7 @@ class PluginSnapshotService:
|
||||
CacheType.PLUGINS,
|
||||
cache_key,
|
||||
snapshot.model_dump(),
|
||||
expire=cls._cache_ttl,
|
||||
expire=PLUGIN_REDIS_TTL,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug(f"缓存插件快照到Redis失败: {cache_key}", LOG_COMMAND, e=e)
|
||||
@@ -395,8 +379,9 @@ class PluginSnapshotService:
|
||||
cache_key = cls._build_cache_key(module)
|
||||
|
||||
# 清理内存缓存
|
||||
if cache_key in cls._memory_cache:
|
||||
del cls._memory_cache[cache_key]
|
||||
memory_cache = cls._get_memory_cache()
|
||||
if cache_key in memory_cache.keys():
|
||||
del memory_cache[cache_key]
|
||||
|
||||
# 清理Redis缓存
|
||||
if cache_config.cache_mode != CacheMode.NONE:
|
||||
@@ -415,6 +400,8 @@ class PluginSnapshotService:
|
||||
"""
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
|
||||
memory_cache = cls._get_memory_cache()
|
||||
|
||||
try:
|
||||
plugins = await PluginInfo.filter(load_status=True).all()
|
||||
count = 0
|
||||
@@ -434,7 +421,7 @@ class PluginSnapshotService:
|
||||
)
|
||||
|
||||
cache_key = cls._build_cache_key(plugin.module)
|
||||
cls._set_to_memory(cache_key, snapshot)
|
||||
memory_cache.set(cache_key, snapshot)
|
||||
count += 1
|
||||
|
||||
logger.info(f"已预热 {count} 个插件的快照缓存", LOG_COMMAND)
|
||||
@@ -445,7 +432,8 @@ class PluginSnapshotService:
|
||||
@classmethod
|
||||
def clear_all_cache(cls):
|
||||
"""清空所有缓存"""
|
||||
cls._memory_cache.clear()
|
||||
if cls._memory_cache:
|
||||
cls._memory_cache.clear()
|
||||
cls._build_locks.clear()
|
||||
logger.info("已清空所有插件快照缓存", LOG_COMMAND)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user