0019-fediverse-outbound-metrics.md 5451 octets

RFC 0019 — Fediverse: observabilité du worker outbound (tracing counters)

  • Auteur : EBO (rustwarden)
  • Date : 2026-05-10
  • Statut : Accepted (auto-revue mainteneur unique 2026-05-10, score 27/35)
  • Apps consommatrices concernées : toute app fediverse en production qui veut surveiller la santé de la file outbound (livraisons, échecs, instances mortes).
  • Plan associé : Phase 5 — production polish.
  • Dépendances : RFC 0011 (file outbound), RFC 0010 (retry/backoff).

Summary

Émettre des événements tracing structurés à chaque transition de FediverseOutboundService::drain_one (pending → delivered, pending → pending+next_retry_at, pending → dead). Ces événements servent de signaux primaires pour les exporters Prometheus / Loki / OpenTelemetry que les apps consommatrices configurent au niveau tracing-subscriber.

Aucune nouvelle dépendance, aucun schéma DB.

Motivation

Sans cette RFC, le worker outbound silencieusement bascule des rows en dead sans aucune trace. En prod un opérateur ne sait pas combien de livraisons réussissent, ni quelle instance pose problème. Le master plan §10 Phase 5 « monitoring file outbound, métriques tracing (compteurs livraisons, retries, instances mortes) » est ouvert.

Non-goals

  • Pas d'exporter Prometheus intégré — les apps configurent leur subscriber.
  • Pas de dashboard Grafana — différé à un livrable doc.
  • Pas de table d'audit — fediverse_outbound_queue contient déjà l'historique persistant ; cette RFC vise la dernière livraison, pas l'historique.

API proposée

Aucune nouvelle API publique. Quatre points d'instrumentation sont ajoutés dans drain_one :

tracing::info!(
    target: "rustwarden::fediverse::outbound",
    activity_id = %item.activity_id,
    target_inbox = %item.target_inbox,
    target_domain = %item.target_domain,
    attempts = updated.attempts,
    event = "delivered",
);

tracing::warn!(
    target: "rustwarden::fediverse::outbound",
    activity_id = …,
    next_retry_at = ?next_retry_at,
    last_error = %err,
    attempts = next_attempts,
    event = "deferred",
);

tracing::error!(
    target: "rustwarden::fediverse::outbound",
    activity_id = …,
    last_error = %err,
    attempts = next_attempts,
    max_attempts = max_attempts,
    event = "dead",
);

tracing::error!(
    target: "rustwarden::fediverse::outbound",
    error = %e,
    event = "drain_failed",
);

Le target rustwarden::fediverse::outbound permet aux exporters de filtrer précisément sans interférer avec les autres logs rustwarden.

Analyse de compatibilité

  • Strictement additif (logs uniquement).
  • Aucune signature publique modifiée.
  • Aucune dépendance supplémentaire — tracing déjà dans le workspace.

Alternatives considérées

Alternative A (recommandée) — tracing events avec target dédié

Pros : zéro dep nouvelle ; compatible avec tous les exporters Rust (tracing-subscriber → Prometheus / Loki / OTEL) ; les apps consommatrices choisissent leur backend.

Alternative B — Crate metrics-rs direct

Cons : dépendance opinionée ; pollue le workspace pour les apps qui n'utilisent pas metrics-rs.

Rejeté.

Alternative C — Pas d'instrumentation, laisser les apps wrap leur propre couche

Cons : duplication ; cohérence des nommages perdue.

Rejeté.

Testing plan

3 tests :

  1. delivered_event_emitted_on_success — capture les events via tracing-subscriber::test et vérifie qu'un event=delivered est émis avec les champs attendus.
  2. deferred_event_emitted_on_failure_below_max_attempts.
  3. dead_event_emitted_at_max_attempts.

Les tests existants de drain_one continuent de passer (les events sont best-effort, ne changent pas la valeur de retour).

Migration guide

### Added (rustwarden-core, feature `experimental-fediverse`)

- Quatre points d'instrumentation `tracing` dans
  `FediverseOutboundService::drain_one` sous le target
  `rustwarden::fediverse::outbound`.

### Migration steps

Aucune obligatoire. Pour exposer les métriques :

```rust
// Apps Prometheus :
let prom_layer = tracing_prometheus::PrometheusBuilder::new()
    .with_target("rustwarden::fediverse::outbound", true)
    .build();
tracing_subscriber::registry().with(prom_layer).init();

## Open questions

- [x] **Naming `target`** : `rustwarden::fediverse::outbound` (cohérent avec la convention rustwarden existante).
- [x] **Niveau** : `info` pour delivered, `warn` pour deferred, `error` pour dead/drain_failed.
- [x] **Champs** : alignés sur le master plan §10 Phase 5.

## Tracking issue

À ouvrir au moment de la PR.

---

## Score d'évaluation

| Critère | Note (1-5) | Commentaire |
|---|---|---|
| Généralité | 4 | Pattern réutilisable pour le reste de la stack rustwarden. |
| Stabilité API | 5 | Strictement additif, logs uniquement. |
| Performance | 5 | `tracing::*!` est zero-cost quand le target est filtré out. |
| Sécurité | 4 | Aide à détecter les attaques de retry / floods. |
| Complexité d'implémentation | 5 | ~40 lignes (4 tracing + 3 tests). |
| Maintenance | 4 | Pas de nouvelle dep. |
| Documentation | 4 | Migration guide complet, target documenté. |
| **Total** | **27/35** | ≥ 25 → Accepted |