API-KA — plateforme centrale : collecte quotidienne des 8 services KA, historisation append-only et API publique sur www.api-ka.com
Python 60.9%
HTML 21%
TypeScript 7.3%
JavaScript 5.2%
CSS 4.8%
Shell 0.8%
1# ============================================2# Projet : API-KA3# Fichier : src/api/routes/health.py4# Node : m3u96b5# Author : Simon-Pierre Boucher6# Contact : contact@spboucher.ai7# Date : 2026-08-168# ============================================9"""Route /health : node (m3u96b), état de la base, dernière collecte par service."""1011from __future__ import annotations1213import socket14from typing import Any1516from fastapi import APIRouter, Depends17from sqlalchemy import func, select18from sqlalchemy.orm import Session1920from src.api.routes import envelope21from src.config import REQUIRED_NODE, SERVICES22from src.database.db import get_db, healthcheck23from src.database.models import CollectionRun, ConnectorHealth24from src.monitoring.connector_health import ALL_STATUSES2526router = APIRouter(tags=["health"])272829@router.get("/health")30def health(db: Session = Depends(get_db)) -> dict[str, Any]:31 """État complet de la plateforme : node, base de données, dernières collectes."""32 hostname = socket.gethostname()33 db_ok = healthcheck()3435 last_collections: dict[str, Any] = {}36 for service in SERVICES:37 last_run = (38 db.execute(39 select(CollectionRun)40 .where(41 CollectionRun.service == service,42 CollectionRun.status.in_(("success", "retried")),43 )44 .order_by(CollectionRun.finished_at.desc())45 .limit(1)46 )47 .scalars()48 .first()49 )50 last_collections[service] = (51 {52 "date_key": last_run.date_key.isoformat(),53 "status": last_run.status,54 "records_count": last_run.records_count,55 "finished_at": last_run.finished_at.isoformat(),56 }57 if last_run58 else None59 )6061 # Résumé de la supervision des connecteurs de l'écosystème (table62 # connector_health, alimentée toutes les 2 h par apika-scheduler).63 connectors = dict.fromkeys(ALL_STATUSES, 0)64 for status, count in db.execute(65 select(ConnectorHealth.status, func.count()).group_by(ConnectorHealth.status)66 ):67 if status in connectors:68 connectors[status] = count6970 data = {71 "status": "ok" if db_ok else "degraded",72 "node": hostname,73 "required_node": REQUIRED_NODE,74 "node_ok": hostname.split(".")[0].lower() == REQUIRED_NODE,75 "database": "ok" if db_ok else "error",76 "last_collections": last_collections,77 "connectors": connectors,78 }79 return envelope(data)80