diff --git a/app/core/cache.py b/app/core/cache.py index d1bb7758..737a74a6 100644 --- a/app/core/cache.py +++ b/app/core/cache.py @@ -4,7 +4,7 @@ from abc import ABC, abstractmethod from functools import wraps from typing import Any, Dict, Optional -from cachetools import TTLCache +from cachetools import TTLCache as CacheToolsTTLCache from cachetools.keys import hashkey from app.core.config import settings @@ -138,9 +138,9 @@ class CacheToolsBackend(CacheBackend): self.maxsize = maxsize self.ttl = ttl # 存储各个 region 的缓存实例,region -> TTLCache - self._region_caches: Dict[str, TTLCache] = {} + self._region_caches: Dict[str, CacheToolsTTLCache] = {} - def __get_region_cache(self, region: str) -> Optional[TTLCache]: + def __get_region_cache(self, region: str) -> Optional[CacheToolsTTLCache]: """ 获取指定区域的缓存实例,如果不存在则返回 None """ @@ -162,7 +162,7 @@ class CacheToolsBackend(CacheBackend): maxsize = kwargs.get("maxsize", self.maxsize) region = self.get_region(region) # 如果该 key 尚未有缓存实例,则创建一个新的 TTLCache 实例 - region_cache = self._region_caches.setdefault(region, TTLCache(maxsize=maxsize, ttl=ttl)) + region_cache = self._region_caches.setdefault(region, CacheToolsTTLCache(maxsize=maxsize, ttl=ttl)) # 设置缓存值 with lock: region_cache[key] = value @@ -348,6 +348,100 @@ def get_cache_backend(maxsize: Optional[int] = 512, ttl: Optional[int] = 1800) - return CacheToolsBackend(maxsize=maxsize, ttl=ttl) +class TTLCache: + """ + TTL缓存类,根据配置自动选择使用Redis或cachetools + + 特性: + - 提供与cachetools.TTLCache相同的接口 + - 根据配置自动选择缓存后端 + - 支持Redis和cachetools的切换 + """ + + def __init__(self, maxsize: int = 128, ttl: int = 600): + """ + 初始化TTL缓存 + + :param maxsize: 缓存的最大条目数 + :param ttl: 缓存的存活时间,单位秒 + """ + self.maxsize = maxsize + self.ttl = ttl + self._backend = get_cache_backend(maxsize=maxsize, ttl=ttl) + + def __getitem__(self, key): + """ + 获取缓存项 + """ + try: + value = self._backend.get(str(key)) + if value is not None: + return value + except Exception as e: + logger.warning(f"缓存获取失败: {e}") + + raise KeyError(key) + + def __setitem__(self, key, value): + """ + 设置缓存项 + """ + try: + self._backend.set(str(key), value, ttl=self.ttl) + except Exception as e: + logger.warning(f"缓存设置失败: {e}") + + def __delitem__(self, key): + """ + 删除缓存项 + """ + try: + self._backend.delete(str(key)) + except Exception as e: + logger.warning(f"缓存删除失败: {e}") + + def __contains__(self, key): + """ + 检查键是否存在 + """ + try: + return self._backend.exists(str(key)) + except Exception as e: + logger.warning(f"缓存检查失败: {e}") + return False + + def get(self, key, default=None): + """ + 获取缓存项,如果不存在返回默认值 + """ + try: + value = self._backend.get(str(key)) + if value is not None: + return value + except Exception as e: + logger.warning(f"缓存获取失败: {e}") + + return default + + def clear(self): + """ + 清空缓存 + """ + try: + self._backend.clear() + except Exception as e: + logger.warning(f"缓存清空失败: {e}") + + def close(self): + """ + 关闭缓存连接 + """ + try: + self._backend.close() + except Exception as e: + logger.warning(f"缓存关闭失败: {e}") + + def cached(region: Optional[str] = None, maxsize: Optional[int] = 512, ttl: Optional[int] = 1800, skip_none: Optional[bool] = True, skip_empty: Optional[bool] = False): """ diff --git a/app/helper/message.py b/app/helper/message.py index 042a9bb3..e4364713 100644 --- a/app/helper/message.py +++ b/app/helper/message.py @@ -10,7 +10,7 @@ from datetime import datetime from typing import Any, Literal, Optional, List, Dict, Union from typing import Callable -from cachetools import TTLCache +from app.core.cache import TTLCache from jinja2 import Template from app.core.config import global_vars diff --git a/app/helper/redis.py b/app/helper/redis.py index 3236ab6d..24c8e60e 100644 --- a/app/helper/redis.py +++ b/app/helper/redis.py @@ -10,10 +10,10 @@ from app.core.event import eventmanager, Event from app.log import logger from app.schemas import ConfigChangeEventData from app.schemas.types import EventType -from app.utils.singleton import SingletonClass +from app.utils.singleton import Singleton -class RedisHelper(metaclass=SingletonClass): +class RedisHelper(metaclass=Singleton): """ Redis连接和操作助手类 diff --git a/app/monitor.py b/app/monitor.py index 164debc6..1d098de6 100644 --- a/app/monitor.py +++ b/app/monitor.py @@ -10,7 +10,7 @@ from threading import Lock from typing import Any, Optional, Dict, List from apscheduler.schedulers.background import BackgroundScheduler -from cachetools import TTLCache +from app.core.cache import TTLCache from watchdog.events import FileSystemEventHandler, FileSystemMovedEvent, FileSystemEvent from watchdog.observers.polling import PollingObserver