# Alerting Rules — TR-069 Exchange Viewer ## Overview Ce document décrit les règles d'alerte configurées pour le système TR-069 Exchange Viewer. Chaque règle définit un seuil critique, les conditions de déclenchement, l'impact attendu et la procédure d'escalade associée. Les métriques sont exposées via le endpoint `/api/v1/health/tr069-exchanges` et les logs structurés JSON. --- ## Alert 1: SSE Active Connections > 100 ### Seuil | Métrique | Condition | Sévérité | |----------|-----------|----------| | `sse.active_connections` | > 100 connexions simultanées | **Warning** | | `sse.active_connections` | > 200 connexions simultanées | **Critical** | ### Description Un nombre élevé de connexions SSE simultanées indique une charge serveur importante. Chaque connexion SSE maintient un socket HTTP ouvert et un listener EventEmitter en mémoire. Au-delà de 100 connexions, le serveur risque une dégradation de performance (latence accrue, consommation mémoire excessive). ### Causes possibles - Pic d'activité : de nombreux opérateurs tracent des devices simultanément - Fuite de connexions : les clients ne ferment pas correctement les connexions EventSource (navigation sans cleanup) - Reconnection storm : perte réseau transitoire provoquant la reconnexion simultanée de tous les clients - Bug client : boucle de reconnexion infinie (EventSource retry sans backoff) ### Impact - Augmentation de la consommation mémoire du processus Node.js - Latence accrue sur les push SSE (chaque nouveau message est dispatché à N listeners) - Risque d'épuisement des file descriptors (limite OS) - Dégradation possible du traitement CWMP si le thread principal est saturé ### Détection ```json // GET /api/v1/health/tr069-exchanges { "sse": { "active_connections": 142, "reconnections_1h": 56 } } ``` Logs structurés : ```json { "level": "warn", "msg": "SSE connection count high", "active_connections": 142, "threshold": 100 } ``` ### Procédure de résolution 1. **Vérifier** le nombre de connexions actives via le health check endpoint 2. **Identifier** les devices avec le plus de connexions (logs : `sse.connect` events par deviceId) 3. **Vérifier** si des connexions zombies existent (connexions ouvertes sans activité > 5 minutes) 4. **Appliquer** les timeouts serveur : les connexions inactives sont fermées après 5 min, les absolues après 2h 5. **Si le problème persiste** : redémarrer le service pour forcer la fermeture de toutes les connexions SSE ### Escalade | Durée | Action | |-------|--------| | 0-5 min | Monitoring automatique, pas d'action | | 5-15 min (Warning) | Vérifier les logs, identifier la cause | | > 15 min (Warning) | Notifier l'équipe Dev via Slack #adam-acs-alerts | | Immédiat (Critical > 200) | Notifier l'équipe Dev + Ops, envisager un restart | | > 30 min (Critical) | Activer le feature flag `FEATURE_SSE_ENABLED=false` (fallback REST polling) | --- ## Alert 2: MongoDB Write Latency p95 > 100ms ### Seuil | Métrique | Condition | Sévérité | |----------|-----------|----------| | `mongodb.write_latency_p95` | > 100ms | **Warning** | | `mongodb.write_latency_p95` | > 500ms | **Critical** | | `mongodb.write_latency_p99` | > 1000ms | **Critical** | ### Description La latence d'écriture MongoDB au percentile 95 reflète la performance de persistance des échanges CWMP. Au-delà de 100ms (p95), les écritures commencent à s'accumuler, ce qui peut provoquer un retard dans la diffusion SSE et une pression mémoire sur le processus. ### Causes possibles - Charge MongoDB élevée (autres opérations concurrentes, compaction, journalisation) - Index manquant ou dégradé sur la collection `cwmp_exchanges` - Disque I/O saturé sur le serveur MongoDB - Collection `cwmp_exchanges` trop volumineuse (TTL cleanup en retard) - Locks MongoDB : opérations bulk ou migrations en cours ### Impact - Retard dans la diffusion SSE des nouveaux échanges (latence end-to-end augmentée) - Activation des retries pour les messages critiques (backoff 1s, 2s, 4s) - En cas de timeout persistant : perte potentielle de messages non-critiques (Empty, Unknown) - Le traitement CWMP n'est jamais impacté (fire-and-forget) ### Détection Logs structurés : ```json { "level": "warn", "msg": "MongoDB write slow", "collection": "cwmp_exchanges", "duration_ms": 145, "deviceId": "abc123", "cwmpMethod": "Inform" } ``` Métriques agrégées (via logs ou Prometheus) : ``` mongodb_write_latency_ms{collection="cwmp_exchanges", quantile="0.95"} 145 mongodb_write_latency_ms{collection="cwmp_exchanges", quantile="0.99"} 320 ``` ### Procédure de résolution 1. **Vérifier** l'état de MongoDB : `db.serverStatus()`, `db.currentOp()` 2. **Vérifier** les index de `cwmp_exchanges` : ```bash mongosh --eval "db.cwmp_exchanges.getIndexes()" ``` 3. **Vérifier** la taille de la collection et le nombre de documents : ```bash mongosh --eval "db.cwmp_exchanges.stats()" ``` 4. **Vérifier** le TTL cleanup (voir Alert 4) 5. **Si les index sont manquants** : recréer via la migration ou manuellement : ```bash mongosh --eval "db.cwmp_exchanges.createIndex({deviceId:1, timestamp:1})" mongosh --eval "db.cwmp_exchanges.createIndex({deviceId:1, sequenceNumber:1}, {unique:true})" mongosh --eval "db.cwmp_exchanges.createIndex({createdAt:1}, {expireAfterSeconds:86400})" ``` 6. **Si la charge est transitoire** : attendre la stabilisation (compaction terminée, etc.) ### Escalade | Durée | Action | |-------|--------| | 0-5 min | Monitoring automatique | | 5-15 min (Warning) | Vérifier les index et la charge MongoDB | | > 15 min (Warning) | Notifier l'équipe Dev | | Immédiat (Critical > 500ms) | Notifier Dev + DBA | | > 30 min (Critical) | Envisager `FEATURE_EXCHANGE_PERSISTENCE=false` pour délester MongoDB | --- ## Alert 3: Message Loss Rate > 0.1% ### Seuil | Métrique | Condition | Sévérité | |----------|-----------|----------| | `exchange.loss_rate` | > 0.1% (1 message sur 1000) | **Critical** | | `exchange.loss_rate` | > 1.0% (1 message sur 100) | **Urgent** | ### Description Le taux de perte de messages représente le pourcentage de messages CWMP capturés par le middleware mais non persistés en MongoDB (après épuisement des retries pour les critiques, ou discard immédiat pour les non-critiques). Un taux > 0.1% indique des défaillances critiques du backend de persistance. ### Causes possibles - Défaillance MongoDB : connexion perdue, timeout, disque plein - Retry exhaustion : 3 retries échoués consécutivement pour les messages critiques - Erreur dans le service `ExchangeStoreService` (bug, exception non catchée) - Saturation de la collection (cap à 5000 messages avec suppression simultanée) - Problème réseau entre l'application et MongoDB ### Impact - Trous dans l'historique des échanges visibles dans le Sequence Viewer - Les opérateurs voient des séquences incomplètes, rendant le debug difficile - Les messages critiques (Inform, SetParameterValues) perdus représentent une perte d'observabilité sur les actions CPE ### Détection Logs structurés : ```json { "level": "error", "msg": "Exchange persistence failed after retries", "deviceId": "abc123", "cwmpMethod": "Inform", "retries": 3, "error": "MongoServerError: connection timeout" } { "level": "warn", "msg": "Non-critical exchange discarded", "deviceId": "abc123", "cwmpMethod": "Empty", "error": "MongoServerError: connection timeout" } ``` Calcul du taux de perte : ``` loss_rate = (messages_discarded / messages_captured) * 100 ``` ### Procédure de résolution 1. **Vérifier** la connectivité MongoDB : health check endpoint, `mongosh` ping 2. **Vérifier** les logs d'erreur pour identifier le pattern de défaillance 3. **Vérifier** l'espace disque disponible sur le serveur MongoDB 4. **Vérifier** que le TTL cleanup fonctionne (pas d'accumulation illimitée) 5. **Si MongoDB est injoignable** : vérifier le réseau, le service mongod, les limites de connexions 6. **Si MongoDB est surchargé** : identifier les opérations concurrentes, envisager un throttle ### Escalade | Durée | Action | |-------|--------| | Immédiat (> 0.1%) | **Alerte critique** — Notifier l'équipe Dev immédiatement | | 0-5 min | Diagnostic rapide : MongoDB up? Index OK? Disk space? | | 5-15 min | Notifier Dev + Ops, vérifier infrastructure MongoDB | | > 15 min | Escalade management, envisager rollback vers fichiers | | Immédiat (> 1.0%) | **Alerte urgente** — Activer `FEATURE_EXCHANGE_PERSISTENCE=false`, diagnostic prioritaire | --- ## Alert 4: TTL Cleanup Lag > 1 Hour ### Seuil | Métrique | Condition | Sévérité | |----------|-----------|----------| | `exchange.ttl_cleanup_lag` | > 1 heure | **Warning** | | `exchange.ttl_cleanup_lag` | > 6 heures | **Critical** | ### Description L'index TTL sur le champ `createdAt` (expire après 86400 secondes = 24h) est géré par un thread interne MongoDB qui s'exécute toutes les 60 secondes. Si le cleanup prend du retard, des documents expirés s'accumulent, augmentant la taille de la collection et dégradant les performances de requête. Le "lag" est mesuré comme la différence entre le plus ancien document présent dans la collection et son heure d'expiration théorique (createdAt + 24h). ### Causes possibles - MongoDB TTL monitor surchargé (collection très volumineuse, beaucoup de documents à supprimer) - Index TTL supprimé ou corrompu - MongoDB en mode de maintenance (locks, compaction) - Charge élevée sur le serveur empêchant le thread TTL de s'exécuter - Bug dans la configuration du TTL (mauvais champ, mauvaise valeur `expireAfterSeconds`) ### Impact - Croissance non contrôlée de la collection `cwmp_exchanges` - Dégradation progressive des performances de lecture (scans plus larges) - Consommation disque accrue - Potentiel dépassement des limites de stockage ### Détection Vérification manuelle du lag : ```bash # Trouver le document le plus ancien mongosh --eval " const oldest = db.cwmp_exchanges.find().sort({createdAt: 1}).limit(1).toArray()[0]; if (oldest) { const expectedExpiry = new Date(oldest.createdAt.getTime() + 86400000); const lag = Date.now() - expectedExpiry.getTime(); print('Oldest createdAt:', oldest.createdAt); print('Expected expiry:', expectedExpiry); print('Lag (ms):', Math.max(0, lag)); print('Lag (hours):', Math.max(0, lag / 3600000).toFixed(2)); } else { print('Collection empty'); } " ``` Vérification de l'index TTL : ```bash mongosh --eval " const indexes = db.cwmp_exchanges.getIndexes(); const ttlIndex = indexes.find(i => i.expireAfterSeconds !== undefined); if (ttlIndex) { print('TTL index found:', JSON.stringify(ttlIndex)); } else { print('WARNING: No TTL index found!'); } " ``` ### Procédure de résolution 1. **Vérifier** que l'index TTL existe et est correctement configuré : ```bash mongosh --eval "db.cwmp_exchanges.getIndexes()" ``` L'index attendu : `{ "createdAt": 1 }` avec `expireAfterSeconds: 86400` 2. **Si l'index TTL est manquant** — le recréer : ```bash mongosh --eval "db.cwmp_exchanges.createIndex({createdAt: 1}, {expireAfterSeconds: 86400})" ``` 3. **Si l'index existe mais le cleanup est en retard** : - Vérifier la charge MongoDB : `db.serverStatus().metrics.ttl` - Vérifier si un grand nombre de documents doivent être supprimés d'un coup - Envisager un nettoyage manuel des plus anciens documents : ```bash mongosh --eval " const cutoff = new Date(Date.now() - 86400000); const result = db.cwmp_exchanges.deleteMany({createdAt: {$lt: cutoff}}); print('Deleted:', result.deletedCount); " ``` 4. **Si MongoDB est en maintenance** : attendre la fin de l'opération, surveiller la reprise du TTL ### Escalade | Durée | Action | |-------|--------| | 0-1h | Monitoring automatique (TTL thread cycle = 60s, léger retard normal) | | 1-3h (Warning) | Vérifier l'existence de l'index TTL, vérifier la charge MongoDB | | 3-6h (Warning) | Notifier l'équipe Dev, envisager un nettoyage manuel | | > 6h (Critical) | Notifier Dev + DBA, nettoyage manuel obligatoire, diagnostic approfondi | | > 24h | Escalade management — la collection grandit sans limite | --- ## Résumé des alertes | # | Alerte | Seuil Warning | Seuil Critical | Métrique | |---|--------|---------------|----------------|----------| | 1 | SSE Active Connections | > 100 | > 200 | `sse.active_connections` | | 2 | MongoDB Write Latency p95 | > 100ms | > 500ms | `mongodb.write_latency_p95` | | 3 | Message Loss Rate | > 0.1% | > 1.0% | `exchange.loss_rate` | | 4 | TTL Cleanup Lag | > 1 heure | > 6 heures | `exchange.ttl_cleanup_lag` | --- ## Configuration des alertes ### Variables d'environnement | Variable | Défaut | Description | |----------|--------|-------------| | `ALERT_SSE_CONNECTIONS_WARNING` | `100` | Seuil warning connexions SSE | | `ALERT_SSE_CONNECTIONS_CRITICAL` | `200` | Seuil critical connexions SSE | | `ALERT_MONGO_LATENCY_P95_WARNING_MS` | `100` | Seuil warning latence MongoDB p95 (ms) | | `ALERT_MONGO_LATENCY_P95_CRITICAL_MS` | `500` | Seuil critical latence MongoDB p95 (ms) | | `ALERT_LOSS_RATE_CRITICAL_PCT` | `0.1` | Seuil critical taux de perte (%) | | `ALERT_TTL_LAG_WARNING_HOURS` | `1` | Seuil warning lag TTL (heures) | | `ALERT_TTL_LAG_CRITICAL_HOURS` | `6` | Seuil critical lag TTL (heures) | ### Intégration avec les systèmes d'alerte Les alertes sont déclenchées via les logs structurés JSON, compatibles avec : - **ELK Stack** : index pattern `adam-acs-*`, filtres sur `level: "error"` ou `level: "warn"` + tags spécifiques - **Datadog** : log-based monitors avec conditions sur les champs JSON - **Prometheus/Grafana** : si le endpoint `/metrics` est exposé, utiliser les alerting rules Prometheus Exemple de règle Prometheus : ```yaml groups: - name: tr069-exchange-viewer rules: - alert: HighSSEConnections expr: adam_acs_sse_active_connections > 100 for: 5m labels: severity: warning annotations: summary: "High SSE connection count" description: "{{ $value }} SSE connections active (threshold: 100)" - alert: MongoWriteLatencyHigh expr: histogram_quantile(0.95, adam_acs_mongodb_write_duration_seconds_bucket{collection="cwmp_exchanges"}) > 0.1 for: 5m labels: severity: warning annotations: summary: "MongoDB write latency p95 > 100ms" description: "p95 latency: {{ $value }}s for cwmp_exchanges writes" - alert: ExchangeMessageLoss expr: rate(adam_acs_exchange_messages_lost_total[5m]) / rate(adam_acs_exchange_messages_captured_total[5m]) > 0.001 for: 1m labels: severity: critical annotations: summary: "Message loss rate exceeds 0.1%" description: "{{ $value | humanizePercentage }} messages lost in last 5 minutes" - alert: TTLCleanupLag expr: adam_acs_exchange_ttl_lag_seconds > 3600 for: 10m labels: severity: warning annotations: summary: "TTL cleanup lag exceeds 1 hour" description: "Oldest expired document is {{ $value | humanizeDuration }} past its TTL" ``` --- ## Contacts d'escalade | Niveau | Contact | Canal | |--------|---------|-------| | L1 — Warning | Équipe Dev adam-acs | Slack #adam-acs-alerts | | L2 — Critical | Lead Dev + Ops | Slack #adam-acs-alerts + mention @oncall | | L3 — Urgent/Prolongé | Management technique | Escalade téléphonique | | DBA (MongoDB) | Équipe DBA | Slack #dba-support |