Fix multi level cache key build and usage (#1066)

* Fix multi level cache key build and usage

* Update build cache key
This commit is contained in:
Wu Clan
2026-02-06 13:42:13 +08:00
committed by GitHub
parent 95aebe1ceb
commit 4d457b2215
5 changed files with 26 additions and 83 deletions
+23 -33
View File
@@ -3,7 +3,6 @@ import functools
from collections.abc import Callable, Sequence
from typing import Any, ParamSpec, TypeVar
from cachebox import make_hash_key
from msgspec import json
from backend.common.cache.local import local_cache_manager
@@ -18,11 +17,8 @@ from backend.utils.serializers import select_columns_serialize, select_list_seri
P = ParamSpec('P')
T = TypeVar('T')
# 哈希缓存键排除参数
_EXCLUDE_PARAMS = frozenset({'db', 'session', 'self', 'cls', 'request', 'response'})
def build_cache_key(
def _build_cache_key(
name: str,
key: str | None,
key_builder: Callable[..., str] | None,
@@ -30,32 +26,18 @@ def build_cache_key(
**kwargs: Any,
) -> str:
"""构建缓存 Key"""
if key_builder:
return f'{name}:{key_builder(*args, **kwargs)}'
if key:
value = kwargs.get(key)
if value is None:
raise errors.ServerError(msg=f'缓存键构建失败,参数 "{key}" 不存在或值为空')
return f'{name}:{value}'
filtered = {k: v for k, v in kwargs.items() if k not in _EXCLUDE_PARAMS and v is not None}
if filtered:
hash_suffix = make_hash_key(*args, **kwargs)
return f'{name}:{hash_suffix}'
if key_builder:
return f'{name}:{key_builder(*args, **kwargs)}'
return name
def user_key_builder() -> str:
"""基于当前用户 ID 生成缓存 Key"""
user_id = ctx.user_id
if user_id is None:
raise errors.ServerError(msg='用户缓存键构建失败')
return str(user_id)
def _serialize_result(result: Any) -> bytes:
"""
序列化缓存结果
@@ -93,6 +75,14 @@ def _deserialize_result(value: bytes) -> Any:
return value
def user_key_builder() -> str:
"""基于当前用户 ID 生成缓存 Key"""
user_id = ctx.user_id
if user_id is None:
raise errors.ServerError(msg='用户缓存键构建失败')
return str(user_id)
def cached( # noqa: C901
name: str,
*,
@@ -113,7 +103,7 @@ def cached( # noqa: C901
def decorator(func: Callable[P, T]) -> Callable[P, T]: # noqa: C901
@functools.wraps(func)
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
cache_key = build_cache_key(name, key, key_builder, *args, **kwargs)
cache_key = _build_cache_key(name, key, key_builder, *args, **kwargs)
# L1: 本地缓存
if settings.CACHE_LOCAL_ENABLED:
@@ -187,27 +177,27 @@ def cache_invalidate( # noqa: C901
invalidate_error = None
try:
invalidate_key = build_cache_key(name, key, key_builder, *args, **kwargs)
# L2 缓存失效
if invalidate_key == name:
await redis_client.delete(invalidate_key)
else:
await redis_client.delete_prefix(invalidate_key)
invalidate_key = _build_cache_key(name, key, key_builder, *args, **kwargs)
# L1 缓存失效
if settings.CACHE_LOCAL_ENABLED:
if invalidate_key == name:
local_cache_manager.delete(invalidate_key)
else:
local_cache_manager.delete_prefix(invalidate_key)
else:
local_cache_manager.delete(invalidate_key)
# 广播失效消息(通知其他节点清除本地缓存)
if settings.CACHE_LOCAL_ENABLED:
if invalidate_key == name:
await cache_pubsub_manager.publish_invalidation(invalidate_key)
else:
await cache_pubsub_manager.publish_invalidation(invalidate_key, is_delete_prefix=True)
else:
await cache_pubsub_manager.publish_invalidation(invalidate_key)
# L2 缓存失效
if invalidate_key == name:
await redis_client.delete_prefix(invalidate_key)
else:
await redis_client.delete(invalidate_key)
except Exception as e:
log.error(f'[Cache] INVALIDATE error: {e}')