"""In-memory TTL cache for expensive scoring and metrics calculations. The cache is a simple dict with timestamps. It is invalidated when tests are validated, scores change, or an explicit ``invalidate`` call is made. Thread-safe: each worker process has its own dict, and the TTL ensures stale data does not persist longer than ``CACHE_TTL`` seconds. """ # Import time import time # Import Any, Optional from typing from typing import Any, Optional # Import Session from sqlalchemy.orm from sqlalchemy.orm import Session # Assign CACHE_TTL = 300 # 5 minutes CACHE_TTL = 300 # 5 minutes # Assign _cache = {} _cache: dict[str, dict[str, Any]] = {} # Define function get def get(key: str) -> Optional[Any]: # noqa: ANN401 # generic cache returns whatever was stored """Return cached value if present and not expired, else None.""" # Assign entry = _cache.get(key) entry = _cache.get(key) # Check: entry is None if entry is None: # Return None return None # Check: time.time() - entry["ts"] > CACHE_TTL if time.time() - entry["ts"] > CACHE_TTL: # Call _cache.pop() _cache.pop(key, None) # Return None return None # Return entry["data"] return entry["data"] # Define function put def put(key: str, data: Any) -> None: # noqa: ANN401 # generic cache accepts any serialisable value """Store *data* under *key* with the current timestamp.""" # Assign _cache[key] = {"data": data, "ts": time.time()} _cache[key] = {"data": data, "ts": time.time()} # Define function invalidate def invalidate(key: Optional[str] = None) -> None: """Remove one key or clear the whole cache.""" # Check: key is None if key is None: # Call _cache.clear() _cache.clear() # Fallback: handle remaining cases else: # Call _cache.pop() _cache.pop(key, None) # ── High-level helpers ──────────────────────────────────────────────── def get_organization_score_cached(db: Session) -> dict: """Cached wrapper around ``calculate_organization_score``.""" # Import calculate_organization_score from app.services.scoring_service from app.services.scoring_service import calculate_organization_score # Assign cached = get("org_score") cached = get("org_score") # Check: cached is not None if cached is not None: # Return cached return cached # Assign result = calculate_organization_score(db) result = calculate_organization_score(db) # Call put() put("org_score", result) # Return result return result # Define function get_operational_metrics_cached def get_operational_metrics_cached(db: Session) -> dict: """Cached wrapper around operational metrics (MTTD, MTTR, efficacy).""" # Import from app.services.operational_metrics_service from app.services.operational_metrics_service import ( calculate_alert_fidelity, calculate_coverage_velocity, calculate_detection_efficacy, calculate_mttd, calculate_mttr, calculate_rejection_rate, calculate_validation_throughput, ) # Assign cached = get("op_metrics") cached = get("op_metrics") # Check: cached is not None if cached is not None: # Return cached return cached # Assign result = { result = { # Literal argument value "mttd": calculate_mttd(db), # Literal argument value "mttr": calculate_mttr(db), # Literal argument value "detection_efficacy": calculate_detection_efficacy(db), # Literal argument value "alert_fidelity": calculate_alert_fidelity(db), # Literal argument value "coverage_velocity": calculate_coverage_velocity(db), # Literal argument value "validation_throughput": calculate_validation_throughput(db), # Literal argument value "rejection_rate": calculate_rejection_rate(db), } # Call put() put("op_metrics", result) # Return result return result