Build lightweight AI agent admin
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
"""
|
||||
带缓存的通用服务基类
|
||||
继承BaseService,添加Redis缓存支持
|
||||
"""
|
||||
from typing import TypeVar, Type, Optional, List, Tuple, Dict, Callable, Any, ClassVar
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.base_model import BaseModel as DBBaseModel
|
||||
from app.base_service import BaseService
|
||||
from utils.redis import CacheManager
|
||||
|
||||
T = TypeVar("T", bound=DBBaseModel)
|
||||
CreateSchema = TypeVar("CreateSchema", bound=BaseModel)
|
||||
UpdateSchema = TypeVar("UpdateSchema", bound=BaseModel)
|
||||
|
||||
|
||||
class CacheService(BaseService[T, CreateSchema, UpdateSchema]):
|
||||
"""
|
||||
带缓存的通用服务基类
|
||||
继承BaseService,添加Redis缓存支持
|
||||
|
||||
子类需要定义:
|
||||
- model: 数据模型类
|
||||
- cache_prefix: 缓存key前缀
|
||||
- cache_expire: 缓存过期时间(秒)
|
||||
|
||||
可选覆盖:
|
||||
- _serialize_for_cache: 自定义序列化方法
|
||||
"""
|
||||
|
||||
# 子类必须定义
|
||||
model: ClassVar[Type[DBBaseModel]]
|
||||
|
||||
# 缓存配置,子类可覆盖
|
||||
cache_prefix: ClassVar[str] = ""
|
||||
cache_expire: ClassVar[int] = 300
|
||||
|
||||
# 缓存key模板
|
||||
CACHE_KEY_DETAIL: ClassVar[str] = "detail:{id}"
|
||||
CACHE_KEY_LIST: ClassVar[str] = "list:page:{page}:size:{size}"
|
||||
|
||||
# 缓存管理器(延迟初始化)
|
||||
_cache_manager: ClassVar[Optional[CacheManager]] = None
|
||||
|
||||
@classmethod
|
||||
def _get_cache(cls) -> CacheManager:
|
||||
"""获取缓存管理器(延迟初始化)"""
|
||||
if cls._cache_manager is None or cls._cache_manager.prefix != f"{cls.cache_prefix}":
|
||||
cls._cache_manager = CacheManager(prefix=cls.cache_prefix)
|
||||
return cls._cache_manager
|
||||
|
||||
@classmethod
|
||||
def _serialize_for_cache(cls, item: Any) -> Dict[str, Any]:
|
||||
"""
|
||||
将model对象序列化为可缓存的字典
|
||||
子类可覆盖此方法自定义序列化逻辑
|
||||
"""
|
||||
return {
|
||||
"id": item.id,
|
||||
"sort": item.sort,
|
||||
"is_deleted": item.is_deleted,
|
||||
"sys_create_datetime": str(item.sys_create_datetime),
|
||||
"sys_update_datetime": str(item.sys_update_datetime),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
async def create(cls, db: AsyncSession, data: CreateSchema) -> Any:
|
||||
"""创建记录并清除列表缓存"""
|
||||
result = await super().create(db, data)
|
||||
# 清除列表缓存
|
||||
await cls._get_cache().delete_pattern("list:*")
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
async def get_by_id(cls, db: AsyncSession, record_id: str) -> Optional[Any]:
|
||||
"""
|
||||
根据ID获取记录(优先从缓存获取)
|
||||
"""
|
||||
cache = cls._get_cache()
|
||||
cache_key = cls.CACHE_KEY_DETAIL.format(id=record_id)
|
||||
|
||||
# 尝试从缓存获取
|
||||
cached = await cache.get(cache_key)
|
||||
if cached:
|
||||
return cached
|
||||
|
||||
# 缓存未命中,从数据库获取
|
||||
result = await super().get_by_id(db, record_id)
|
||||
if result:
|
||||
# 序列化并写入缓存
|
||||
cache_data = cls._serialize_for_cache(result)
|
||||
await cache.set(cache_key, cache_data, cls.cache_expire)
|
||||
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
async def get_by_id_no_cache(cls, db: AsyncSession, record_id: str) -> Optional[Any]:
|
||||
"""根据ID获取记录(不使用缓存)"""
|
||||
return await super().get_by_id(db, record_id)
|
||||
|
||||
@classmethod
|
||||
async def get_list(
|
||||
cls,
|
||||
db: AsyncSession,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
filters: Optional[List[Any]] = None
|
||||
) -> Tuple[List[Any], int]:
|
||||
"""
|
||||
获取列表(优先从缓存获取,仅缓存无过滤条件的查询)
|
||||
"""
|
||||
# 有过滤条件时不使用缓存
|
||||
if filters:
|
||||
return await super().get_list(db, page, page_size, filters)
|
||||
|
||||
cache = cls._get_cache()
|
||||
cache_key = cls.CACHE_KEY_LIST.format(page=page, size=page_size)
|
||||
|
||||
# 尝试从缓存获取
|
||||
cached = await cache.get(cache_key)
|
||||
if cached:
|
||||
return cached.get("items", []), cached.get("total", 0)
|
||||
|
||||
# 缓存未命中,从数据库获取
|
||||
items, total = await super().get_list(db, page, page_size, filters)
|
||||
|
||||
# 序列化并写入缓存
|
||||
cache_data = {
|
||||
"items": [cls._serialize_for_cache(item) for item in items],
|
||||
"total": total
|
||||
}
|
||||
await cache.set(cache_key, cache_data, cls.cache_expire)
|
||||
|
||||
return items, total
|
||||
|
||||
@classmethod
|
||||
async def get_list_no_cache(
|
||||
cls,
|
||||
db: AsyncSession,
|
||||
page: int = 1,
|
||||
page_size: int = 20,
|
||||
filters: Optional[List[Any]] = None
|
||||
) -> Tuple[List[Any], int]:
|
||||
"""获取列表(不使用缓存)"""
|
||||
return await super().get_list(db, page, page_size, filters)
|
||||
|
||||
@classmethod
|
||||
async def update(
|
||||
cls,
|
||||
db: AsyncSession,
|
||||
record_id: str,
|
||||
data: UpdateSchema
|
||||
) -> Optional[Any]:
|
||||
"""更新记录并清除相关缓存"""
|
||||
result = await super().update(db, record_id, data)
|
||||
if result:
|
||||
cache = cls._get_cache()
|
||||
# 清除单条记录缓存
|
||||
await cache.delete(cls.CACHE_KEY_DETAIL.format(id=record_id))
|
||||
# 清除列表缓存
|
||||
await cache.delete_pattern("list:*")
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
async def delete(
|
||||
cls,
|
||||
db: AsyncSession,
|
||||
record_id: str,
|
||||
hard: bool = False
|
||||
) -> bool:
|
||||
"""删除记录并清除相关缓存"""
|
||||
result = await super().delete(db, record_id, hard)
|
||||
if result:
|
||||
cache = cls._get_cache()
|
||||
# 清除单条记录缓存
|
||||
await cache.delete(cls.CACHE_KEY_DETAIL.format(id=record_id))
|
||||
# 清除列表缓存
|
||||
await cache.delete_pattern("list:*")
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
async def clear_cache(cls, record_id: Optional[str] = None) -> int:
|
||||
"""
|
||||
手动清除缓存
|
||||
|
||||
:param record_id: 指定ID则只清除该记录缓存,否则清除所有缓存
|
||||
:return: 清除的key数量
|
||||
"""
|
||||
cache = cls._get_cache()
|
||||
if record_id:
|
||||
return await cache.delete(cls.CACHE_KEY_DETAIL.format(id=record_id))
|
||||
else:
|
||||
return await cache.delete_pattern("*")
|
||||
|
||||
@classmethod
|
||||
async def refresh_cache(cls, db: AsyncSession, record_id: str) -> bool:
|
||||
"""
|
||||
刷新指定记录的缓存
|
||||
|
||||
:param record_id: 记录ID
|
||||
:return: 是否成功
|
||||
"""
|
||||
# 先删除缓存
|
||||
await cls._get_cache().delete(cls.CACHE_KEY_DETAIL.format(id=record_id))
|
||||
# 重新获取(会自动写入缓存)
|
||||
result = await cls.get_by_id(db, record_id)
|
||||
return result is not None
|
||||
|
||||
@classmethod
|
||||
async def get_cache_stats(cls, record_id: str) -> Dict[str, Any]:
|
||||
"""
|
||||
获取缓存状态信息
|
||||
|
||||
:param record_id: 记录ID
|
||||
:return: 缓存状态信息
|
||||
"""
|
||||
cache = cls._get_cache()
|
||||
cache_key = cls.CACHE_KEY_DETAIL.format(id=record_id)
|
||||
exists = await cache.exists(cache_key)
|
||||
ttl = await cache.ttl(cache_key) if exists else -2
|
||||
|
||||
return {
|
||||
"key": f"{cache.prefix}{cache_key}",
|
||||
"exists": exists,
|
||||
"ttl": ttl
|
||||
}
|
||||
|
||||
@classmethod
|
||||
async def import_from_excel(
|
||||
cls,
|
||||
db: AsyncSession,
|
||||
file_content: bytes,
|
||||
row_processor: Optional[Callable[[Dict[str, Any]], Optional[Any]]] = None
|
||||
) -> Tuple[int, int]:
|
||||
"""从Excel导入数据并清除列表缓存"""
|
||||
result = await super().import_from_excel(db, file_content, row_processor)
|
||||
# 清除列表缓存
|
||||
await cls._get_cache().delete_pattern("list:*")
|
||||
return result
|
||||
Reference in New Issue
Block a user