SLO, budgets d'erreur et propagation des traces
Kit sections 11 et 15, exigences OBSE-001, OBSE-005 et OBSE-012. Version anglaise : en/slo.md.
Cibles
| Service | Routes | Disponibilité | Latence |
|---|---|---|---|
control_plane_api | toutes les autres routes /v1 | 99,5 % | 95 % des requêtes sous 1 s |
model_gateway | /v1/gateway/* | 99,5 % | 95 % sous 1 s |
tool_gateway | /v1/tools/* | 99,5 % | 95 % sous 1 s |
realtime | /v1/realtime* | 99,5 % | 95 % sous 1 s |
worker | jobs de python -m eai.worker | 99 % de jobs réussis |
Les cibles de la route sont lues dans la table eai.service_slos (V169, ADR-0157), écrite par PUT /v1/telemetry/slo/targets/{service} (platform_admin seul, corps {availability, latency_seconds, latency_objective, reason?}, audité telemetry.slo.target.update, 404 slo_service_unknown) ; chaque service de la réponse indique target_source: database | settings. Un service sans ligne garde les valeurs par défaut réglées par EAI_SLO_AVAILABILITY_TARGETS, EAI_SLO_LATENCY_TARGETS_SECONDS, EAI_SLO_LATENCY_OBJECTIVE ; la fenêtre est bornée par EAI_SLO_RETENTION_MINUTES (configuration.md). Une valeur invalide est refusée au démarrage en production (eai.security.startup). Les règles Prometheus portent les valeurs par défaut ci-dessus : changer une cible demande de mettre à jour aussi deploy/observability/slo/eai-slo-rules.yaml et ses tests promtool.
Budgets et taux de brûlage
- Budget autorisé = (1 - cible) x requêtes de la fenêtre. Budget restant = 1 - mauvaises requêtes / budget autorisé (négatif quand le budget est dépassé).
- Taux de brûlage = part de mauvaises requêtes / (1 - cible) : 1 consomme exactement le budget sur la période.
- Mauvaise requête : statut 5xx pour la disponibilité, durée au-dessus du seuil pour la latence.
Alertes de brûlage (multi-fenêtres)
| Alerte | Condition | Sévérité |
|---|---|---|
EaiSloAvailabilityFastBurn | taux d'erreur > 14,4 x 0,5 % sur 1 h et 5 min, pendant 2 min | critical |
EaiSloAvailabilitySlowBurn | taux d'erreur > 6 x 0,5 % sur 6 h et 1 h, pendant 15 min | warning |
EaiSloLatencyFastBurn | requêtes lentes > 14,4 x 5 % sur 1 h et 5 min, pendant 2 min | critical |
EaiSloWorkerFastBurn | jobs en échec > 14,4 x 1 % sur 1 h et 5 min, pendant 2 min | critical |
Vérification : promtool check rules deploy/observability/slo/eai-slo-rules.yaml et promtool test rules deploy/observability/slo/tests/eai-slo-rules.test.yaml (tests/test_observability_slo.py).
Écran du portail
La plateforme ne livre pas de serveur de tableaux de bord (ADR-0169). Les budgets se lisent dans l'écran SLO et budgets d'erreur du portail (/observability/slo, guide), alimenté par la route ci-dessous ; la vue de toute la flotte sur 30 jours vient des règles d'enregistrement eai:* et des alertes de brûlage, lues dans Prometheus et Alertmanager. Un Grafana exploité par le client peut lire les mêmes règles (EAI_GRAFANA_URL).
Route GET /v1/telemetry/slo
Paramètres : window_minutes (1 à EAI_SLO_RETENTION_MINUTES, défaut 60) et tenant_id (platform_admin seulement). Rôles : platform_admin (toute la plateforme ou un tenant), tenant_admin, auditor et viewer (leur tenant uniquement). Chaque lecture est auditée (telemetry.slo.read). Codes d'erreur : forbidden, tenant_required, slo_scope_forbidden, slo_window_invalid, slo_targets_invalid.
Réponse par service : requests, errors, over_latency_target, latency_target_seconds, puis availability et latency avec target, bad, ratio, budget_remaining et burn_rate.
Source : le middleware HTTP de l'API compte chaque requête servie (gabarit de route, statut, durée, tenant de l'appelant) dans des cases d'une minute gardées en mémoire par réplique. La route donne donc la vue de la réplique interrogée ; la vue de toute la flotte sur 30 jours vient des règles Prometheus, calculées sur les mêmes mesures (eai_http_requests_total, eai_http_request_duration_seconds).
Propagation des traces
- HTTP : le span serveur de l'API continue le
traceparentreçu ;eai.llm.route,eai.llm.provider_calleteai.tool.invokesont ses descendants, et l'amont (fournisseur LLM, outil) reçoit letraceparentdu span courant. - File :
scheduler.publishouvreeai.event.publishet écrittraceparentettracestatedans les en-têtes de l'événement (NATS oueai.event_outbox, y compris les réveils des workers média). Le joboutboxouvreeai.event.delivercomme enfant de cetraceparentpuiseai.event.dispatch, et les audits écrits pendant la livraison portent le mêmetrace_id. - Le worker initialise OpenTelemetry avec les réglages
EAI_OTEL_*de l'API et vide l'exportateur à l'arrêt. - Preuve :
services/control-plane/tests/test_trace_end_to_end.pyavec le vraiotelcol-contrib(deploy/observability/tools/fetch-toolchain.sh otelcol).