semantics

This commit is contained in:
2026-03-27 21:27:31 +03:00
parent 7c85552132
commit 2ed66bfebc
182 changed files with 21186 additions and 10254 deletions

View File

@@ -3,14 +3,15 @@
# @SEMANTICS: health, aggregation, dashboards
# @PURPOSE: Business logic for aggregating dashboard health status from validation records.
# @LAYER: Domain/Service
# @RELATION: [DEPENDS_ON] ->[backend.src.models.llm.ValidationRecord]
# @RELATION: [DEPENDS_ON] ->[backend.src.core.superset_client.SupersetClient]
# @RELATION: [DEPENDS_ON] ->[backend.src.core.task_manager.cleanup.TaskCleanupService]
# @RELATION: [DEPENDS_ON] ->[ValidationRecord]
# @RELATION: [DEPENDS_ON] ->[SupersetClient]
# @RELATION: [DEPENDS_ON] ->[TaskCleanupService]
# @RELATION: [DEPENDS_ON] ->[TaskManager]
from typing import List, Dict, Any, Optional, Tuple
from typing import List, Dict, Any, Optional, Tuple, cast
import time
from sqlalchemy.orm import Session
from sqlalchemy import func, desc
from sqlalchemy import func
import os
from ..models.llm import ValidationRecord
from ..schemas.health import DashboardHealthItem, HealthSummaryResponse
@@ -20,6 +21,10 @@ from ..core.task_manager.cleanup import TaskCleanupService
from ..core.task_manager import TaskManager
def _empty_dashboard_meta() -> Dict[str, Optional[str]]:
return cast(Dict[str, Optional[str]], {"slug": None, "title": None})
# [DEF:HealthService:Class]
# @COMPLEXITY: 4
# @PURPOSE: Aggregate latest dashboard validation state and manage persisted health report lifecycle.
@@ -27,12 +32,12 @@ from ..core.task_manager import TaskManager
# @POST: Exposes health summary aggregation and validation report deletion operations.
# @SIDE_EFFECT: Maintains in-memory dashboard metadata caches and may coordinate cleanup through collaborators.
# @DATA_CONTRACT: Input[Session, Optional[Any]] -> Output[HealthSummaryResponse|bool]
# @RELATION: [DEPENDS_ON] ->[sqlalchemy.orm.Session]
# @RELATION: [DEPENDS_ON] ->[backend.src.models.llm.ValidationRecord]
# @RELATION: [DEPENDS_ON] ->[backend.src.schemas.health.DashboardHealthItem]
# @RELATION: [DEPENDS_ON] ->[backend.src.schemas.health.HealthSummaryResponse]
# @RELATION: [CALLS] ->[backend.src.core.superset_client.SupersetClient]
# @RELATION: [CALLS] ->[backend.src.core.task_manager.cleanup.TaskCleanupService]
# @RELATION: [DEPENDS_ON] ->[ValidationRecord]
# @RELATION: [DEPENDS_ON] ->[DashboardHealthItem]
# @RELATION: [DEPENDS_ON] ->[HealthSummaryResponse]
# @RELATION: [DEPENDS_ON] ->[SupersetClient]
# @RELATION: [DEPENDS_ON] ->[TaskCleanupService]
# @RELATION: [DEPENDS_ON] ->[TaskManager]
class HealthService:
_dashboard_summary_cache: Dict[
str, Tuple[float, Dict[str, Dict[str, Optional[str]]]]
@@ -50,8 +55,7 @@ class HealthService:
# @POST: Service is ready to aggregate summaries and delete health reports.
# @SIDE_EFFECT: Initializes per-instance dashboard metadata cache.
# @DATA_CONTRACT: Input[db: Session, config_manager: Optional[Any]] -> Output[HealthService]
# @RELATION: [BINDS_TO] ->[backend.src.services.health_service.HealthService]
# @RELATION: [DEPENDS_ON] ->[sqlalchemy.orm.Session]
# @RELATION: [BINDS_TO] ->[HealthService]
def __init__(self, db: Session, config_manager=None):
self.db = db
self.config_manager = config_manager
@@ -66,10 +70,9 @@ class HealthService:
# @POST: Numeric dashboard ids for known environments are cached when discoverable.
# @SIDE_EFFECT: May call Superset dashboard list API once per referenced environment.
# @DATA_CONTRACT: Input[records: List[ValidationRecord]] -> Output[None]
# @RELATION: [DEPENDS_ON] ->[backend.src.models.llm.ValidationRecord]
# @RELATION: [DEPENDS_ON] ->[backend.src.core.superset_client.SupersetClient]
# @RELATION: [CALLS] ->[config_manager.get_environments]
# @RELATION: [CALLS] ->[backend.src.core.superset_client.SupersetClient.get_dashboards_summary]
# @RELATION: [DEPENDS_ON] ->[ValidationRecord]
# @RELATION: [DEPENDS_ON] ->[ConfigManager]
# @RELATION: [DEPENDS_ON] ->[SupersetClient]
def _prime_dashboard_meta_cache(self, records: List[ValidationRecord]) -> None:
if not self.config_manager or not records:
return
@@ -98,23 +101,26 @@ class HealthService:
env = environments.get(environment_id)
if not env:
for dashboard_id in dashboard_ids:
self._dashboard_meta_cache[(environment_id, dashboard_id)] = {
"slug": None,
"title": None,
}
self._dashboard_meta_cache[(environment_id, dashboard_id)] = (
_empty_dashboard_meta()
)
continue
try:
cached_meta = self.__class__._dashboard_summary_cache.get(
environment_id
)
cache_is_fresh = (
dashboard_meta_map: Dict[str, Dict[str, Optional[str]]]
if (
cached_meta is not None
and (time.monotonic() - cached_meta[0])
< self.__class__._dashboard_summary_cache_ttl_seconds
)
if cache_is_fresh:
dashboard_meta_map = cached_meta[1]
):
cached_meta_data = cast(
Tuple[float, Dict[str, Dict[str, Optional[str]]]],
cached_meta,
)
dashboard_meta_map = cached_meta_data[1]
else:
dashboards = SupersetClient(env).get_dashboards_summary()
dashboard_meta_map = {
@@ -133,7 +139,7 @@ class HealthService:
self._dashboard_meta_cache[(environment_id, dashboard_id)] = (
dashboard_meta_map.get(
dashboard_id,
{"slug": None, "title": None},
_empty_dashboard_meta(),
)
)
except Exception as exc:
@@ -143,10 +149,9 @@ class HealthService:
exc,
)
for dashboard_id in dashboard_ids:
self._dashboard_meta_cache[(environment_id, dashboard_id)] = {
"slug": None,
"title": None,
}
self._dashboard_meta_cache[(environment_id, dashboard_id)] = (
_empty_dashboard_meta()
)
# [/DEF:_prime_dashboard_meta_cache:Function]
@@ -162,20 +167,20 @@ class HealthService:
normalized_dashboard_id = str(dashboard_id or "").strip()
normalized_environment_id = str(environment_id or "").strip()
if not normalized_dashboard_id:
return {"slug": None, "title": None}
return _empty_dashboard_meta()
if not normalized_dashboard_id.isdigit():
return {"slug": normalized_dashboard_id, "title": None}
if not self.config_manager or not normalized_environment_id:
return {"slug": None, "title": None}
return _empty_dashboard_meta()
cache_key = (normalized_environment_id, normalized_dashboard_id)
cached = self._dashboard_meta_cache.get(cache_key)
if cached is not None:
return cached
meta = {"slug": None, "title": None}
meta = _empty_dashboard_meta()
self._dashboard_meta_cache[cache_key] = meta
return meta
@@ -188,10 +193,10 @@ class HealthService:
# @POST: Returns HealthSummaryResponse with counts and latest record row per dashboard.
# @SIDE_EFFECT: May call Superset API to resolve dashboard metadata.
# @DATA_CONTRACT: Input[environment_id: Optional[str]] -> Output[HealthSummaryResponse]
# @RELATION: [CALLS] ->[self._prime_dashboard_meta_cache]
# @RELATION: [CALLS] ->[self._resolve_dashboard_meta]
# @RELATION: [CALLS] ->[_prime_dashboard_meta_cache]
# @RELATION: [CALLS] ->[_resolve_dashboard_meta]
async def get_health_summary(
self, environment_id: str = None
self, environment_id: str = ""
) -> HealthSummaryResponse:
"""
@PURPOSE: Aggregates the latest validation status for all dashboards.
@@ -228,7 +233,8 @@ class HealthService:
unknown_count = 0
for rec in records:
status = rec.status.upper()
record = cast(Any, rec)
status = str(record.status or "").upper()
if status == "PASS":
pass_count += 1
elif status == "WARN":
@@ -239,18 +245,34 @@ class HealthService:
unknown_count += 1
status = "UNKNOWN"
meta = self._resolve_dashboard_meta(rec.dashboard_id, rec.environment_id)
record_id = str(record.id or "")
dashboard_id = str(record.dashboard_id or "")
resolved_environment_id = (
str(record.environment_id)
if record.environment_id is not None
else None
)
response_environment_id = (
resolved_environment_id
if resolved_environment_id is not None
else "unknown"
)
task_id = str(record.task_id) if record.task_id is not None else None
summary = str(record.summary) if record.summary is not None else None
timestamp = cast(Any, record.timestamp)
meta = self._resolve_dashboard_meta(dashboard_id, resolved_environment_id)
items.append(
DashboardHealthItem(
record_id=rec.id,
dashboard_id=rec.dashboard_id,
record_id=record_id,
dashboard_id=dashboard_id,
dashboard_slug=meta.get("slug"),
dashboard_title=meta.get("title"),
environment_id=rec.environment_id or "unknown",
environment_id=response_environment_id,
status=status,
last_check=rec.timestamp,
task_id=rec.task_id,
summary=rec.summary,
last_check=timestamp,
task_id=task_id,
summary=summary,
)
)
@@ -275,11 +297,9 @@ class HealthService:
# @POST: Returns True only when a matching record was deleted.
# @SIDE_EFFECT: Deletes DB rows, optional screenshot file, and optional task/log persistence.
# @DATA_CONTRACT: Input[record_id: str, task_manager: Optional[TaskManager]] -> Output[bool]
# @RELATION: [DEPENDS_ON] ->[backend.src.models.llm.ValidationRecord]
# @RELATION: [DEPENDS_ON] ->[backend.src.core.task_manager.TaskManager]
# @RELATION: [CALLS] ->[os.path.exists]
# @RELATION: [CALLS] ->[os.remove]
# @RELATION: [CALLS] ->[backend.src.core.task_manager.cleanup.TaskCleanupService.delete_task_with_logs]
# @RELATION: [DEPENDS_ON] ->[ValidationRecord]
# @RELATION: [DEPENDS_ON] ->[TaskManager]
# @RELATION: [DEPENDS_ON] ->[TaskCleanupService]
def delete_validation_report(
self, record_id: str, task_manager: Optional[TaskManager] = None
) -> bool: