""" Redis-backed cache for EngineeringReport results, keyed by (github_url, head_sha). Best-effort: any Redis error is logged and treated as a cache miss / no-op write, never raised to callers. """ from functools import lru_cache import redis from app.core.config import get_settings from app.core.logger import get_logger from app.models.report import EngineeringReport logger = get_logger(__name__) @lru_cache() def get_redis_client() -> redis.Redis: settings = get_settings() return redis.Redis.from_url(settings.redis_url, decode_responses=True) def _cache_key(github_url: str, head_sha: str) -> str: return f"analysis:{github_url}:{head_sha}" def get_cached_report(github_url: str, head_sha: str) -> EngineeringReport | None: """Return a cached EngineeringReport, or None on a miss or Redis error.""" try: client = get_redis_client() raw = client.get(_cache_key(github_url, head_sha)) except Exception as exc: logger.warning("Cache read failed", extra={"error": str(exc)}) return None if raw is None: return None try: return EngineeringReport.model_validate_json(str(raw)) except Exception as exc: logger.warning("Cached report failed to deserialize", extra={"error": str(exc)}) return None def set_cached_report(github_url: str, head_sha: str, report: EngineeringReport) -> None: """Best-effort write of an EngineeringReport to the cache with a TTL.""" try: settings = get_settings() client = get_redis_client() client.set( _cache_key(github_url, head_sha), report.model_dump_json(), ex=settings.cache_ttl_seconds, ) except Exception as exc: logger.warning("Cache write failed", extra={"error": str(exc)}) def _clear_redis_client_cache() -> None: # test helper only get_redis_client.cache_clear()