Add in-memory read cache with CUD-based invalidation

This commit is contained in:
Chris
2026-04-03 02:32:38 +08:00
parent e912d1498e
commit 55e640f2fb
6 changed files with 194 additions and 20 deletions

View File

@@ -53,6 +53,7 @@ from app.security.admin_guard import require_admin_principal
from app.security.api_client_auth import hash_api_key
from app.services.idp_admin_service import ProviderAdminService
from app.services.idp_catalog_sync import sync_from_provider
from app.services.runtime_cache import runtime_cache
from app.core.config import get_settings
router = APIRouter(
@@ -161,9 +162,16 @@ def list_companies(
limit: int = Query(default=100, ge=1, le=500),
offset: int = Query(default=0, ge=0),
) -> ListResponse:
cache_key = f"admin:companies:{keyword or ''}:{limit}:{offset}"
cached = runtime_cache.get(cache_key)
if isinstance(cached, ListResponse):
return cached
repo = CompaniesRepository(db)
items, total = repo.list(keyword=keyword, limit=limit, offset=offset)
return ListResponse(items=[_company_item(i) for i in items], total=total, limit=limit, offset=offset)
result = ListResponse(items=[_company_item(i) for i in items], total=total, limit=limit, offset=offset)
runtime_cache.set(cache_key, result, ttl_seconds=20)
return result
@router.post("/companies", response_model=CompanyItem)
@@ -251,6 +259,11 @@ def list_sites(
limit: int = Query(default=100, ge=1, le=500),
offset: int = Query(default=0, ge=0),
) -> ListResponse:
cache_key = f"admin:sites:{keyword or ''}:{company_key or ''}:{limit}:{offset}"
cached = runtime_cache.get(cache_key)
if isinstance(cached, ListResponse):
return cached
companies_repo = CompaniesRepository(db)
sites_repo = SitesRepository(db)
company_id = None
@@ -264,7 +277,9 @@ def list_sites(
company_map = {c.id: c for c in companies}
items, total = sites_repo.list(keyword=keyword, company_id=company_id, limit=limit, offset=offset)
response_items = [_site_item(i, company_map[i.company_id]) for i in items if i.company_id in company_map]
return ListResponse(items=response_items, total=total, limit=limit, offset=offset)
result = ListResponse(items=response_items, total=total, limit=limit, offset=offset)
runtime_cache.set(cache_key, result, ttl_seconds=20)
return result
@router.post("/sites", response_model=SiteItem)
@@ -375,9 +390,16 @@ def list_systems(
limit: int = Query(default=100, ge=1, le=500),
offset: int = Query(default=0, ge=0),
) -> ListResponse:
cache_key = f"admin:systems:{keyword or ''}:{status_filter or ''}:{limit}:{offset}"
cached = runtime_cache.get(cache_key)
if isinstance(cached, ListResponse):
return cached
repo = SystemsRepository(db)
items, total = repo.list(keyword=keyword, status=status_filter, limit=limit, offset=offset)
return ListResponse(items=[_system_item(i) for i in items], total=total, limit=limit, offset=offset)
result = ListResponse(items=[_system_item(i) for i in items], total=total, limit=limit, offset=offset)
runtime_cache.set(cache_key, result, ttl_seconds=20)
return result
@router.post("/systems", response_model=SystemItem)
@@ -404,6 +426,11 @@ def list_roles(
limit: int = Query(default=100, ge=1, le=500),
offset: int = Query(default=0, ge=0),
) -> ListResponse:
cache_key = f"admin:roles:{keyword or ''}:{system_key or ''}:{status_filter or ''}:{limit}:{offset}"
cached = runtime_cache.get(cache_key)
if isinstance(cached, ListResponse):
return cached
systems_repo = SystemsRepository(db)
roles_repo = RolesRepository(db)
@@ -433,7 +460,9 @@ def list_roles(
for row in rows
if row.system_id in system_map
]
return ListResponse(items=items, total=total, limit=limit, offset=offset)
result = ListResponse(items=items, total=total, limit=limit, offset=offset)
runtime_cache.set(cache_key, result, ttl_seconds=20)
return result
@router.post("/roles", response_model=RoleItem)
@@ -751,9 +780,17 @@ def list_members(
limit: int = Query(default=100, ge=1, le=500),
offset: int = Query(default=0, ge=0),
) -> ListResponse:
is_active_key = "" if is_active is None else ("1" if is_active else "0")
cache_key = f"admin:members:{keyword or ''}:{is_active_key}:{limit}:{offset}"
cached = runtime_cache.get(cache_key)
if isinstance(cached, ListResponse):
return cached
repo = UsersRepository(db)
rows, total = repo.list(keyword=keyword, is_active=is_active, limit=limit, offset=offset)
return ListResponse(items=[_member_item(r) for r in rows], total=total, limit=limit, offset=offset)
result = ListResponse(items=[_member_item(r) for r in rows], total=total, limit=limit, offset=offset)
runtime_cache.set(cache_key, result, ttl_seconds=20)
return result
@router.post("/members", response_model=MemberItem)
@@ -950,14 +987,21 @@ def list_api_clients(
limit: int = Query(default=100, ge=1, le=500),
offset: int = Query(default=0, ge=0),
) -> ListResponse:
cache_key = f"admin:api_clients:{keyword or ''}:{status_filter or ''}:{limit}:{offset}"
cached = runtime_cache.get(cache_key)
if isinstance(cached, ListResponse):
return cached
repo = ApiClientsRepository(db)
items, total = repo.list(keyword=keyword, status=status_filter, limit=limit, offset=offset)
return ListResponse(
result = ListResponse(
items=[ApiClientItem.model_validate(i, from_attributes=True) for i in items],
total=total,
limit=limit,
offset=offset,
)
runtime_cache.set(cache_key, result, ttl_seconds=20)
return result
@router.post("/sync/from-provider")