import asyncio import time import asyncpg from app.models.models import Target from app.schemas.overview import DatabaseOverviewOut from app.services.collector import build_target_dsn from app.services.infra_probe import get_disk_space_provider from app.services.overview_collector import collect_overview _CACHE_TTL_SECONDS = 20 _cache: dict[int, tuple[float, DatabaseOverviewOut]] = {} _locks: dict[int, asyncio.Lock] = {} def _get_lock(target_id: int) -> asyncio.Lock: if target_id not in _locks: _locks[target_id] = asyncio.Lock() return _locks[target_id] async def get_target_overview(target: Target) -> DatabaseOverviewOut: now = time.time() cached = _cache.get(target.id) if cached and (now - cached[0]) < _CACHE_TTL_SECONDS: return cached[1] lock = _get_lock(target.id) async with lock: cached = _cache.get(target.id) now = time.time() if cached and (now - cached[0]) < _CACHE_TTL_SECONDS: return cached[1] conn = await asyncpg.connect(dsn=build_target_dsn(target)) try: payload = await collect_overview( conn=conn, disk_provider=get_disk_space_provider(), target_host=target.host, cache_ttl_seconds=_CACHE_TTL_SECONDS, ) finally: await conn.close() _cache[target.id] = (time.time(), payload) return payload