mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
fix redis key
This commit is contained in:
+27
-29
@@ -205,31 +205,6 @@ class CacheBackend(ABC):
|
|||||||
"""
|
"""
|
||||||
return f"region:{region}" if region else "region:default"
|
return f"region:{region}" if region else "region:default"
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_cache_key(func, args, kwargs) -> str:
|
|
||||||
"""
|
|
||||||
根据函数和参数生成缓存键
|
|
||||||
|
|
||||||
:param func: 函数对象
|
|
||||||
:param args: 位置参数
|
|
||||||
:param kwargs: 关键字参数
|
|
||||||
:return: 缓存键
|
|
||||||
"""
|
|
||||||
signature = inspect.signature(func)
|
|
||||||
# 绑定传入的参数并应用默认值
|
|
||||||
bound = signature.bind(*args, **kwargs)
|
|
||||||
bound.apply_defaults()
|
|
||||||
# 忽略第一个参数,如果它是实例(self)或类(cls)
|
|
||||||
parameters = list(signature.parameters.keys())
|
|
||||||
if parameters and parameters[0] in ("self", "cls"):
|
|
||||||
bound.arguments.pop(parameters[0], None)
|
|
||||||
# 按照函数签名顺序提取参数值列表
|
|
||||||
keys = [
|
|
||||||
bound.arguments[param] for param in signature.parameters if param in bound.arguments
|
|
||||||
]
|
|
||||||
# 使用有序参数生成缓存键
|
|
||||||
return f"{func.__name__}_{hashkey(*keys)}"
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_redis() -> bool:
|
def is_redis() -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -764,7 +739,7 @@ class FileBackend(CacheBackend):
|
|||||||
for item in cache_path.iterdir():
|
for item in cache_path.iterdir():
|
||||||
if item.is_file():
|
if item.is_file():
|
||||||
with open(item, 'r') as f:
|
with open(item, 'r') as f:
|
||||||
yield item.name, f.read()
|
yield item.as_posix(), f.read()
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -877,7 +852,7 @@ class AsyncFileBackend(AsyncCacheBackend):
|
|||||||
async for item in cache_path.iterdir():
|
async for item in cache_path.iterdir():
|
||||||
if await item.is_file():
|
if await item.is_file():
|
||||||
async with aiofiles.open(item, 'r') as f:
|
async with aiofiles.open(item, 'r') as f:
|
||||||
yield item.name, await f.read()
|
yield item.as_posix(), await f.read()
|
||||||
|
|
||||||
async def close(self) -> None:
|
async def close(self) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -971,6 +946,29 @@ def cached(region: Optional[str] = None, maxsize: Optional[int] = 1024, ttl: Opt
|
|||||||
|
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
|
|
||||||
|
def __get_cache_key(args, kwargs) -> str:
|
||||||
|
"""
|
||||||
|
根据函数和参数生成缓存键
|
||||||
|
|
||||||
|
:param args: 位置参数
|
||||||
|
:param kwargs: 关键字参数
|
||||||
|
:return: 缓存键
|
||||||
|
"""
|
||||||
|
signature = inspect.signature(func)
|
||||||
|
# 绑定传入的参数并应用默认值
|
||||||
|
bound = signature.bind(*args, **kwargs)
|
||||||
|
bound.apply_defaults()
|
||||||
|
# 忽略第一个参数,如果它是实例(self)或类(cls)
|
||||||
|
parameters = list(signature.parameters.keys())
|
||||||
|
if parameters and parameters[0] in ("self", "cls"):
|
||||||
|
bound.arguments.pop(parameters[0], None)
|
||||||
|
# 按照函数签名顺序提取参数值列表
|
||||||
|
keys = [
|
||||||
|
bound.arguments[param] for param in signature.parameters if param in bound.arguments
|
||||||
|
]
|
||||||
|
# 使用有序参数生成缓存键
|
||||||
|
return f"{func.__name__}_{hashkey(*keys)}"
|
||||||
|
|
||||||
# 获取缓存区
|
# 获取缓存区
|
||||||
cache_region = region if region is not None else f"{func.__module__}.{func.__name__}"
|
cache_region = region if region is not None else f"{func.__module__}.{func.__name__}"
|
||||||
|
|
||||||
@@ -982,7 +980,7 @@ def cached(region: Optional[str] = None, maxsize: Optional[int] = 1024, ttl: Opt
|
|||||||
@wraps(func)
|
@wraps(func)
|
||||||
async def async_wrapper(*args, **kwargs):
|
async def async_wrapper(*args, **kwargs):
|
||||||
# 获取缓存键
|
# 获取缓存键
|
||||||
cache_key = cache_backend.get_cache_key(func, args, kwargs)
|
cache_key = __get_cache_key(args, kwargs)
|
||||||
# 尝试获取缓存
|
# 尝试获取缓存
|
||||||
cached_value = cache_backend.get(cache_key, region=cache_region)
|
cached_value = cache_backend.get(cache_key, region=cache_region)
|
||||||
if should_cache(cached_value) and is_valid_cache_value(cache_key, cached_value, cache_region):
|
if should_cache(cached_value) and is_valid_cache_value(cache_key, cached_value, cache_region):
|
||||||
@@ -1010,7 +1008,7 @@ def cached(region: Optional[str] = None, maxsize: Optional[int] = 1024, ttl: Opt
|
|||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
# 获取缓存键
|
# 获取缓存键
|
||||||
cache_key = cache_backend.get_cache_key(func, args, kwargs)
|
cache_key = __get_cache_key(args, kwargs)
|
||||||
# 尝试获取缓存
|
# 尝试获取缓存
|
||||||
cached_value = cache_backend.get(cache_key, region=cache_region)
|
cached_value = cache_backend.get(cache_key, region=cache_region)
|
||||||
if should_cache(cached_value) and is_valid_cache_value(cache_key, cached_value, cache_region):
|
if should_cache(cached_value) and is_valid_cache_value(cache_key, cached_value, cache_region):
|
||||||
|
|||||||
+32
-20
@@ -140,20 +140,32 @@ class RedisHelper(metaclass=Singleton):
|
|||||||
logger.error(f"Failed to set Redis maxmemory or policy: {e}")
|
logger.error(f"Failed to set Redis maxmemory or policy: {e}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_region(region: Optional[str] = "DEFAULT"):
|
def __get_region(region: Optional[str] = "DEFAULT"):
|
||||||
"""
|
"""
|
||||||
获取缓存的区
|
获取缓存的区
|
||||||
"""
|
"""
|
||||||
return f"region:{region}" if region else "region:default"
|
return f"region:{region}" if region else "region:default"
|
||||||
|
|
||||||
def get_redis_key(self, region: str, key: str) -> str:
|
def __make_redis_key(self, region: str, key: str) -> str:
|
||||||
"""
|
"""
|
||||||
获取缓存Key
|
获取缓存Key
|
||||||
"""
|
"""
|
||||||
# 使用region作为缓存键的一部分
|
# 使用region作为缓存键的一部分
|
||||||
region = self.get_region(quote(region))
|
region = self.__get_region(quote(region))
|
||||||
return f"{region}:key:{quote(key)}"
|
return f"{region}:key:{quote(key)}"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __get_original_key(redis_key: str) -> str:
|
||||||
|
"""
|
||||||
|
从Redis键中提取原始key
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
parts = redis_key.split(":key:")
|
||||||
|
return parts[-1]
|
||||||
|
except Exception as e:
|
||||||
|
logger.warn(f"Failed to parse redis key: {redis_key}, error: {e}")
|
||||||
|
return redis_key
|
||||||
|
|
||||||
def set(self, key: str, value: Any, ttl: Optional[int] = None,
|
def set(self, key: str, value: Any, ttl: Optional[int] = None,
|
||||||
region: Optional[str] = "DEFAULT", **kwargs) -> None:
|
region: Optional[str] = "DEFAULT", **kwargs) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -167,7 +179,7 @@ class RedisHelper(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self._connect()
|
self._connect()
|
||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.__make_redis_key(region, key)
|
||||||
# 对值进行序列化
|
# 对值进行序列化
|
||||||
serialized_value = serialize(value)
|
serialized_value = serialize(value)
|
||||||
kwargs.pop("maxsize", None)
|
kwargs.pop("maxsize", None)
|
||||||
@@ -185,7 +197,7 @@ class RedisHelper(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self._connect()
|
self._connect()
|
||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.__make_redis_key(region, key)
|
||||||
return self.client.exists(redis_key) == 1
|
return self.client.exists(redis_key) == 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to exists key: {key} region: {region}, error: {e}")
|
logger.error(f"Failed to exists key: {key} region: {region}, error: {e}")
|
||||||
@@ -201,7 +213,7 @@ class RedisHelper(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self._connect()
|
self._connect()
|
||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.__make_redis_key(region, key)
|
||||||
value = self.client.get(redis_key)
|
value = self.client.get(redis_key)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
return deserialize(value)
|
return deserialize(value)
|
||||||
@@ -219,7 +231,7 @@ class RedisHelper(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self._connect()
|
self._connect()
|
||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.__make_redis_key(region, key)
|
||||||
self.client.delete(redis_key)
|
self.client.delete(redis_key)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to delete key: {key} in region: {region}, error: {e}")
|
logger.error(f"Failed to delete key: {key} in region: {region}, error: {e}")
|
||||||
@@ -233,7 +245,7 @@ class RedisHelper(metaclass=Singleton):
|
|||||||
try:
|
try:
|
||||||
self._connect()
|
self._connect()
|
||||||
if region:
|
if region:
|
||||||
cache_region = self.get_region(quote(region))
|
cache_region = self.__get_region(quote(region))
|
||||||
redis_key = f"{cache_region}:key:*"
|
redis_key = f"{cache_region}:key:*"
|
||||||
with self.client.pipeline() as pipe:
|
with self.client.pipeline() as pipe:
|
||||||
for key in self.client.scan_iter(redis_key):
|
for key in self.client.scan_iter(redis_key):
|
||||||
@@ -256,17 +268,17 @@ class RedisHelper(metaclass=Singleton):
|
|||||||
try:
|
try:
|
||||||
self._connect()
|
self._connect()
|
||||||
if region:
|
if region:
|
||||||
cache_region = self.get_region(quote(region))
|
cache_region = self.__get_region(quote(region))
|
||||||
redis_key = f"{cache_region}:key:*"
|
redis_key = f"{cache_region}:key:*"
|
||||||
for key in self.client.scan_iter(redis_key):
|
for key in self.client.scan_iter(redis_key):
|
||||||
value = self.client.get(key)
|
value = self.client.get(key)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
yield key, deserialize(value)
|
yield self.__get_original_key(key), deserialize(value)
|
||||||
else:
|
else:
|
||||||
for key in self.client.scan_iter("*"):
|
for key in self.client.scan_iter("*"):
|
||||||
value = self.client.get(key)
|
value = self.client.get(key)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
yield key, deserialize(value)
|
yield self.__get_original_key(key), deserialize(value)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to get items from Redis, region: {region}, error: {e}")
|
logger.error(f"Failed to get items from Redis, region: {region}, error: {e}")
|
||||||
|
|
||||||
@@ -367,18 +379,18 @@ class AsyncRedisHelper(metaclass=Singleton):
|
|||||||
logger.error(f"Failed to set Redis maxmemory or policy (async): {e}")
|
logger.error(f"Failed to set Redis maxmemory or policy (async): {e}")
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_region(region: Optional[str] = "DEFAULT"):
|
def __get_region(region: Optional[str] = "DEFAULT"):
|
||||||
"""
|
"""
|
||||||
获取缓存的区
|
获取缓存的区
|
||||||
"""
|
"""
|
||||||
return f"region:{region}" if region else "region:default"
|
return f"region:{region}" if region else "region:default"
|
||||||
|
|
||||||
def get_redis_key(self, region: str, key: str) -> str:
|
def __make_redis_key(self, region: str, key: str) -> str:
|
||||||
"""
|
"""
|
||||||
获取缓存Key
|
获取缓存Key
|
||||||
"""
|
"""
|
||||||
# 使用region作为缓存键的一部分
|
# 使用region作为缓存键的一部分
|
||||||
region = self.get_region(quote(region))
|
region = self.__get_region(quote(region))
|
||||||
return f"{region}:key:{quote(key)}"
|
return f"{region}:key:{quote(key)}"
|
||||||
|
|
||||||
async def set(self, key: str, value: Any, ttl: Optional[int] = None,
|
async def set(self, key: str, value: Any, ttl: Optional[int] = None,
|
||||||
@@ -394,7 +406,7 @@ class AsyncRedisHelper(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await self._connect()
|
await self._connect()
|
||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.__make_redis_key(region, key)
|
||||||
# 对值进行序列化
|
# 对值进行序列化
|
||||||
serialized_value = serialize(value)
|
serialized_value = serialize(value)
|
||||||
kwargs.pop("maxsize", None)
|
kwargs.pop("maxsize", None)
|
||||||
@@ -412,7 +424,7 @@ class AsyncRedisHelper(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await self._connect()
|
await self._connect()
|
||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.__make_redis_key(region, key)
|
||||||
result = await self.client.exists(redis_key)
|
result = await self.client.exists(redis_key)
|
||||||
return result == 1
|
return result == 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -429,7 +441,7 @@ class AsyncRedisHelper(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await self._connect()
|
await self._connect()
|
||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.__make_redis_key(region, key)
|
||||||
value = await self.client.get(redis_key)
|
value = await self.client.get(redis_key)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
return deserialize(value)
|
return deserialize(value)
|
||||||
@@ -447,7 +459,7 @@ class AsyncRedisHelper(metaclass=Singleton):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await self._connect()
|
await self._connect()
|
||||||
redis_key = self.get_redis_key(region, key)
|
redis_key = self.__make_redis_key(region, key)
|
||||||
await self.client.delete(redis_key)
|
await self.client.delete(redis_key)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to delete key (async): {key} in region: {region}, error: {e}")
|
logger.error(f"Failed to delete key (async): {key} in region: {region}, error: {e}")
|
||||||
@@ -461,7 +473,7 @@ class AsyncRedisHelper(metaclass=Singleton):
|
|||||||
try:
|
try:
|
||||||
await self._connect()
|
await self._connect()
|
||||||
if region:
|
if region:
|
||||||
cache_region = self.get_region(quote(region))
|
cache_region = self.__get_region(quote(region))
|
||||||
redis_key = f"{cache_region}:key:*"
|
redis_key = f"{cache_region}:key:*"
|
||||||
async with self.client.pipeline() as pipe:
|
async with self.client.pipeline() as pipe:
|
||||||
async for key in self.client.scan_iter(redis_key):
|
async for key in self.client.scan_iter(redis_key):
|
||||||
@@ -484,7 +496,7 @@ class AsyncRedisHelper(metaclass=Singleton):
|
|||||||
try:
|
try:
|
||||||
await self._connect()
|
await self._connect()
|
||||||
if region:
|
if region:
|
||||||
cache_region = self.get_region(quote(region))
|
cache_region = self.__get_region(quote(region))
|
||||||
redis_key = f"{cache_region}:key:*"
|
redis_key = f"{cache_region}:key:*"
|
||||||
async for key in self.client.scan_iter(redis_key):
|
async for key in self.client.scan_iter(redis_key):
|
||||||
value = await self.client.get(key)
|
value = await self.client.get(key)
|
||||||
|
|||||||
Reference in New Issue
Block a user