Merge pull request #3751 from InfinityPacer/feature/cache

This commit is contained in:
jxxghp
2025-01-19 01:02:54 +08:00
committed by GitHub
3 changed files with 44 additions and 34 deletions

View File

@@ -1,7 +1,6 @@
import inspect import inspect
import os import os
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from collections import defaultdict
from functools import wraps from functools import wraps
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
@@ -83,8 +82,15 @@ class CacheToolsBackend(CacheBackend):
""" """
self.maxsize = maxsize self.maxsize = maxsize
self.ttl = ttl self.ttl = ttl
# 存储各个 region 的缓存实例region -> {key -> TTLCache} # 存储各个 region 的缓存实例region -> TTLCache
self._region_caches: Dict[str, Dict[str, TTLCache]] = defaultdict(dict) self._region_caches: Dict[str, TTLCache] = {}
def __get_region_cache(self, region: str) -> Optional[TTLCache]:
"""
获取指定区域的缓存实例,如果不存在则返回 None
"""
region = self.get_region(region)
return self._region_caches.get(region)
def set(self, key: str, value: Any, ttl: int = None, region: str = DEFAULT_CACHE_REGION, **kwargs) -> None: def set(self, key: str, value: Any, ttl: int = None, region: str = DEFAULT_CACHE_REGION, **kwargs) -> None:
""" """
@@ -100,13 +106,9 @@ class CacheToolsBackend(CacheBackend):
maxsize = kwargs.get("maxsize", self.maxsize) maxsize = kwargs.get("maxsize", self.maxsize)
region = self.get_region(region) region = self.get_region(region)
# 如果该 key 尚未有缓存实例,则创建一个新的 TTLCache 实例 # 如果该 key 尚未有缓存实例,则创建一个新的 TTLCache 实例
region_cache = self._region_caches[region] region_cache = self._region_caches.setdefault(region, TTLCache(maxsize=maxsize, ttl=ttl))
if key not in region_cache:
region_cache[key] = TTLCache(maxsize=maxsize, ttl=ttl)
# 为每个 key 获取独立的缓存实例
cache = region_cache[key]
# 设置缓存值 # 设置缓存值
cache[key] = value region_cache[key] = value
def get(self, key: str, region: str = DEFAULT_CACHE_REGION) -> Any: def get(self, key: str, region: str = DEFAULT_CACHE_REGION) -> Any:
""" """
@@ -116,13 +118,10 @@ class CacheToolsBackend(CacheBackend):
:param region: 缓存的区 :param region: 缓存的区
:return: 返回缓存的值,如果缓存不存在返回 None :return: 返回缓存的值,如果缓存不存在返回 None
""" """
region = self.get_region(region) region_cache = self.__get_region_cache(region)
region_cache = self._region_caches[region] if region_cache is None:
if key not in region_cache:
return None return None
# 获取缓存实例并返回缓存值 return region_cache.get(key)
cache = region_cache[key]
return cache.get(key)
def delete(self, key: str, region: str = DEFAULT_CACHE_REGION) -> None: def delete(self, key: str, region: str = DEFAULT_CACHE_REGION) -> None:
""" """
@@ -131,13 +130,10 @@ class CacheToolsBackend(CacheBackend):
:param key: 缓存的键 :param key: 缓存的键
:param region: 缓存的区 :param region: 缓存的区
""" """
region = self.get_region(region) region_cache = self.__get_region_cache(region)
region_cache = self._region_caches[region] if region_cache is None:
if key not in region_cache:
return None return None
# 获取缓存实例并删除指定的缓存 del region_cache[key]
cache = region_cache[key]
del cache[key]
def clear(self, region: Optional[str] = None) -> None: def clear(self, region: Optional[str] = None) -> None:
""" """
@@ -146,14 +142,14 @@ class CacheToolsBackend(CacheBackend):
:param region: 缓存的区 :param region: 缓存的区
""" """
if region: if region:
region = self.get_region(region) # 清理指定缓存区
region_cache = self._region_caches[region] region_cache = self.__get_region_cache(region)
for cache in region_cache.values(): if region_cache:
cache.clear() region_cache.clear()
else: else:
# 清除所有区域的缓存
for region_cache in self._region_caches.values(): for region_cache in self._region_caches.values():
for cache in region_cache.values(): region_cache.clear()
cache.clear()
class RedisBackend(CacheBackend): class RedisBackend(CacheBackend):
@@ -248,7 +244,7 @@ def get_cache_backend(maxsize: int = 1000, ttl: int = 1800) -> CacheBackend:
return CacheToolsBackend(maxsize=maxsize, ttl=ttl) return CacheToolsBackend(maxsize=maxsize, ttl=ttl)
def cached(region: str = DEFAULT_CACHE_REGION, maxsize: int = 1000, ttl: int = 1800, def cached(region: Optional[str] = None, maxsize: int = 1000, ttl: int = 1800,
skip_none: bool = True, skip_empty: bool = False): skip_none: bool = True, skip_empty: bool = False):
""" """
自定义缓存装饰器,支持为每个 key 动态传递 maxsize 和 ttl 自定义缓存装饰器,支持为每个 key 动态传递 maxsize 和 ttl
@@ -294,16 +290,21 @@ def cached(region: str = DEFAULT_CACHE_REGION, maxsize: int = 1000, ttl: int = 1
elif value.default is not inspect.Parameter.empty: elif value.default is not inspect.Parameter.empty:
# 没有传递参数时使用默认值 # 没有传递参数时使用默认值
resolved_kwargs[param] = value.default resolved_kwargs[param] = value.default
# 构造缓存键 # 构造缓存键忽略实例self 或 cls
return f"{func.__name__}_{hashkey(*args, **resolved_kwargs)}" params_to_hash = args[1:] if len(args) > 1 else []
return f"{func.__name__}_{hashkey(*params_to_hash, **resolved_kwargs)}"
def decorator(func): def decorator(func):
# 获取缓存区
cache_region = region if region is not None else f"{func.__module__}.{func.__name__}"
@wraps(func) @wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
# 获取缓存键 # 获取缓存键
cache_key = get_cache_key(func, args, kwargs) cache_key = get_cache_key(func, args, kwargs)
# 尝试获取缓存 # 尝试获取缓存
cached_value = cache_backend.get(cache_key, region=region) cached_value = cache_backend.get(cache_key, region=cache_region)
if should_cache(cached_value): if should_cache(cached_value):
return cached_value return cached_value
# 执行函数并缓存结果 # 执行函数并缓存结果
@@ -312,9 +313,19 @@ def cached(region: str = DEFAULT_CACHE_REGION, maxsize: int = 1000, ttl: int = 1
if not should_cache(result): if not should_cache(result):
return result return result
# 设置缓存(如果有传入的 maxsize 和 ttl则覆盖默认值 # 设置缓存(如果有传入的 maxsize 和 ttl则覆盖默认值
cache_backend.set(cache_key, result, ttl=ttl, maxsize=maxsize, region=region) cache_backend.set(cache_key, result, ttl=ttl, maxsize=maxsize, region=cache_region)
return result return result
def cache_clear():
"""
清理缓存区
"""
# 清理缓存区
cache_backend.clear(region=cache_region)
print(f"{cache_region} region cache is cleared")
wrapper.cache_region = cache_region
wrapper.cache_clear = cache_clear
return wrapper return wrapper
return decorator return decorator

View File

@@ -6,7 +6,7 @@ from ..tmdb import TMDb
class Trending(TMDb): class Trending(TMDb):
_urls = {"trending": "/trending/%s/%s"} _urls = {"trending": "/trending/%s/%s"}
@cached(maxsize=1, ttl=43200) @cached(maxsize=1024, ttl=43200)
def _trending(self, media_type="all", time_window="day", page=1): def _trending(self, media_type="all", time_window="day", page=1):
""" """
Get trending, TTLCache 12 hours Get trending, TTLCache 12 hours

View File

@@ -549,7 +549,6 @@ class Scheduler(metaclass=Singleton):
""" """
清理缓存 清理缓存
""" """
TorrentsChain().clear_cache()
SchedulerChain().clear_cache() SchedulerChain().clear_cache()
def user_auth(self): def user_auth(self):