diff --git a/app/core/cache.py b/app/core/cache.py index 5c34d830..421cf6cc 100644 --- a/app/core/cache.py +++ b/app/core/cache.py @@ -10,7 +10,7 @@ from typing import Any, Dict, Optional, Generator, AsyncGenerator, Tuple import aiofiles import aioshutil from anyio import Path as AsyncPath -from cachetools import TTLCache as CacheToolsTTLCache +from cachetools import TTLCache as MemoryTTLCache from cachetools.keys import hashkey from app.core.config import settings @@ -249,12 +249,12 @@ class AsyncCacheBackend(ABC): return settings.CACHE_BACKEND_TYPE == "redis" -class CacheToolsBackend(CacheBackend): +class MemoryBackend(CacheBackend): """ 基于 `cachetools.TTLCache` 实现的缓存后端 """ - def __init__(self, maxsize: Optional[int] = 1024, ttl: Optional[int] = 1800): + def __init__(self, maxsize: Optional[int] = None, ttl: Optional[int] = None): """ 初始化缓存实例 @@ -264,9 +264,9 @@ class CacheToolsBackend(CacheBackend): self.maxsize = maxsize self.ttl = ttl # 存储各个 region 的缓存实例,region -> TTLCache - self._region_caches: Dict[str, CacheToolsTTLCache] = {} + self._region_caches: Dict[str, MemoryTTLCache] = {} - def __get_region_cache(self, region: str) -> Optional[CacheToolsTTLCache]: + def __get_region_cache(self, region: str) -> Optional[MemoryTTLCache]: """ 获取指定区域的缓存实例,如果不存在则返回 None """ @@ -276,19 +276,18 @@ class CacheToolsBackend(CacheBackend): def set(self, key: str, value: Any, ttl: Optional[int] = None, region: Optional[str] = DEFAULT_CACHE_REGION, **kwargs) -> None: """ - 设置缓存值支持每个 key 独立配置 TTL 和 Maxsize + 设置缓存值支持每个 key 独立配置 TTL :param key: 缓存的键 :param value: 缓存的值 - :param ttl: 缓存的存活时间,单位秒如果未传入则使用默认值 + :param ttl: 缓存的存活时间,不传入为永久缓存,单位秒 :param region: 缓存的区 - :param kwargs: maxsize: 缓存的最大条目数如果未传入则使用默认值 """ ttl = ttl or self.ttl maxsize = kwargs.get("maxsize", self.maxsize) region = self.get_region(region) # 如果该 key 尚未有缓存实例,则创建一个新的 TTLCache 实例 - region_cache = self._region_caches.setdefault(region, CacheToolsTTLCache(maxsize=maxsize, ttl=ttl)) + region_cache = self._region_caches.setdefault(region, MemoryTTLCache(maxsize=maxsize, ttl=ttl)) # 设置缓存值 with lock: region_cache[key] = value @@ -394,7 +393,7 @@ class RedisBackend(CacheBackend): :param key: 缓存的键 :param value: 缓存的值 - :param ttl: 缓存的存活时间,单位秒如果未传入则使用默认值 + :param ttl: 缓存的存活时间,未传入则为永久缓存,单位秒 :param region: 缓存的区 :param kwargs: kwargs """ @@ -475,7 +474,7 @@ class AsyncRedisBackend(AsyncCacheBackend): :param key: 缓存的键 :param value: 缓存的值 - :param ttl: 缓存的存活时间,单位秒如果未传入则使用默认值 + :param ttl: 缓存的存活时间,未传入则为永久缓存,单位秒 :param region: 缓存的区 :param kwargs: kwargs """ @@ -764,7 +763,7 @@ class AsyncFileBackend(AsyncCacheBackend): def FileCache(base: Path = settings.TEMP_PATH, ttl: Optional[int] = None) -> CacheBackend: """ - 获取文件缓存后端实例(Redis或文件系统) + 获取文件缓存后端实例(Redis或文件系统),ttl仅在Redis环境中有效 """ if settings.CACHE_BACKEND_TYPE == "redis": # 如果使用 Redis,则设置缓存的存活时间为配置的天数转换为秒 @@ -776,7 +775,7 @@ def FileCache(base: Path = settings.TEMP_PATH, ttl: Optional[int] = None) -> Cac def AsyncFileCache(base: Path = settings.TEMP_PATH, ttl: Optional[int] = None) -> AsyncCacheBackend: """ - 获取文件异步缓存后端实例(Redis或文件系统) + 获取文件异步缓存后端实例(Redis或文件系统),ttl仅在Redis环境中有效 """ if settings.CACHE_BACKEND_TYPE == "redis": # 如果使用 Redis,则设置缓存的存活时间为配置的天数转换为秒 @@ -786,23 +785,24 @@ def AsyncFileCache(base: Path = settings.TEMP_PATH, ttl: Optional[int] = None) - return AsyncFileBackend(base=base) -def Cache(maxsize: Optional[int] = 512, ttl: Optional[int] = 1800) -> CacheBackend: +def Cache(maxsize: Optional[int] = None, ttl: Optional[int] = None) -> CacheBackend: """ - 根据配置获取缓存后端实例(内存或Redis) + 根据配置获取缓存后端实例(内存或Redis),maxsize仅在未启用Redis时生效 - :param maxsize: 缓存的最大条目数,仅使用cachetools时生效 + :param maxsize: 缓存的最大条目数,仅使用cachetools时生效,不传入默认1024 :param ttl: 缓存的默认存活时间,单位秒 :return: 返回缓存后端实例 """ if settings.CACHE_BACKEND_TYPE == "redis": return RedisBackend(ttl=ttl) else: - return CacheToolsBackend(maxsize=maxsize, ttl=ttl) + # 使用内存缓存,maxsize需要有值,默认1024 + return MemoryBackend(maxsize=maxsize or 1024, ttl=ttl) class TTLCache: """ - TTL缓存类,根据配置自动选择使用Redis或cachetools + TTL缓存类,根据配置自动选择使用Redis或cachetools,maxsize仅在未启用Redis时生效 特性: - 提供与cachetools.TTLCache相同的接口 @@ -811,7 +811,7 @@ class TTLCache: """ def __init__(self, region: Optional[str] = DEFAULT_CACHE_REGION, - maxsize: int = 128, ttl: int = 1800): + maxsize: int = None, ttl: int = None): """ 初始化TTL缓存 @@ -914,14 +914,14 @@ class TTLCache: logger.warning(f"缓存关闭失败: {e}") -def cached(region: Optional[str] = None, maxsize: Optional[int] = 512, ttl: Optional[int] = 1800, +def cached(region: Optional[str] = None, maxsize: Optional[int] = None, ttl: Optional[int] = None, skip_none: Optional[bool] = True, skip_empty: Optional[bool] = False): """ 自定义缓存装饰器,支持为每个 key 动态传递 maxsize 和 ttl :param region: 缓存的区 - :param maxsize: 缓存的最大条目数,默认值为 512 - :param ttl: 缓存的存活时间,单位秒,默认值为 1800 + :param maxsize: 缓存的最大条目数 + :param ttl: 缓存的存活时间,单位秒,未传入则为永久缓存,单位秒 :param skip_none: 跳过 None 缓存,默认为 True :param skip_empty: 跳过空值缓存(如 None, [], {}, "", set()),默认为 False :return: 装饰器函数