InfraGuard

Mises à jour en direct (Reverb + interrogation)

Les deux façons dont les écrans se rafraîchissent d'eux-mêmes — les envois instantanés par WebSocket Reverb et une interrogation légère toutes les 30 secondes avec un jeton de changement rev très économique — et pourquoi la console ne casse jamais lorsque les WebSockets sont désactivés.

Vue d’ensemble — à quoi cela sert

Les tableaux de bord d’InfraGuard se mettent à jour sans rechargement de page. Ce rafraîchissement automatique repose sur deux mécanismes.

Mécanisme Comment Latence Utilisé par
WebSocket Reverb Serveur → navigateur, envoi instantané (piloté par événements) millisecondes les tâches en direct qui diffusent leur progression sous forme de ticks
Interrogation légère Le navigateur fait un GET sur /…/live à intervalle régulier jusqu’à 30 s la plupart des tableaux de bord (Santé, Serveurs, Trafic, Service, Sécurité, Alertes …)

Une règle de conception résume tout :

Le direct est une amélioration posée par-dessus des données persistées. Chaque écran affiche d’abord les données enregistrées en base, et les mises à jour temps réel viennent s’ajouter par-dessus. Ainsi, même si Reverb (le serveur WebSocket) est arrêté, bloqué par un pare-feu ou en cours de redémarrage, l’écran ne casse jamais. Lorsque l’envoi n’est pas disponible, l’interrogation prend le relais (dégradation élégante).

En pratique, presque tous les écrans fonctionnent par interrogation. Le WebSocket Reverb est installé et câblé, et il alimente aujourd’hui exactement une fonctionnalité : l’émulation distante du diagnostic de sécurité (Émulation distante · Diagnostic de sécurité), où il diffuse les ticks de progression par hôte. Tous les autres écrans en direct se rafraîchissent par interrogation toutes les 30 secondes, complétée par un jeton de détection de changement économique, rev.


Quand l’utiliser

Il s’agit d’une référence conceptuelle. Ce n’est pas un écran doté d’une route en direct : elle s’adresse aux exploitants et aux ingénieurs qui souhaitent comprendre :


Disposition

Architecture à deux chemins

[données persistées]  server_status · infr_db_metric · blacklist_info · …
      │
      ▼ (chargement initial : le serveur injecte du JSON data-* dans la vue)
[écran du navigateur]  ← rendu instantané (complet sans le direct)
      ▲                          ▲
      │ (A) interrogation         │ (B) envoi Reverb
      │  GET /…/live (≤30s)       │  événement WS 'tick'
      │  redessine si rev↑ seult  │  ShouldBroadcastNow
   [contrôleur Laravel]        [serveur Reverb]

Topologie de Reverb

Élément Valeur Source
Bibliothèques client laravel-echo + pusher-js import dynamique (exclu du bundle principal)

Les détails de connexion du WebSocket sont configurés à l’installation. L’exploitant se contente d’ouvrir l’écran — il n’y a rien à paramétrer.


Comment l’utiliser

Exploitants — rien à faire

Le direct est automatique. Laissez un écran ouvert et l’interrogation récupère les dernières valeurs toutes les 30 secondes ; si le WebSocket est actif, les écrans pilotés par événements se mettent à jour instantanément. Pour économiser l’énergie, l’interrogation se met en pause tant que l’onglet est en arrière-plan et reprend lorsque vous y revenez.

Activer le WebSocket Reverb (facultatif)

L’envoi par WebSocket est configuré à l’installation par votre interlocuteur de déploiement — ce n’est pas une bascule accessible à l’exploitant dans la console. Si vous avez besoin d’envois temps réel, contactez votre administrateur ou l’éditeur.

Un envoi WebSocket désactivé n’est pas une erreur. C’est un interrupteur d’arrêt volontaire — les écrans en direct continuent de fonctionner avec la seule interrogation.

Ce que fait réellement l’interrogation

// Motif représentatif (p. ex. service-overview)
poll_ms: 30000,
this._poll = setInterval(() => {
    if (this.live && !document.hidden) this.poll_tick();   // ignoré quand l’onglet est en arrière-plan
}, this.poll_ms);
// poll_tick → GET /service/live → re-rendu uniquement lorsque le rev de la réponse a changé

Le rev côté serveur est le signal de changement le plus économique possible. Par exemple, l’écran des métriques serveur utilise le MAX(seq) de la table historique server_status comme rev : cette valeur n’augmente que lorsque le collecteur insère un nouvel instantané.

// App\Services\Metric\ServerMetricService::rev()
return (int) DB::connection('legacy')->table('server_status')->max('seq');

La seule tâche en direct qui utilise l’envoi Reverb — l’émulation distante

L’émulation distante du Diagnostic de sécurité diffuse un tick de progression chaque fois qu’un hôte se termine.


Sources de données

Fichier Rôle
resources/js/echo.js L’unique constructeur Echo de l’application (SOT) — import dynamique · contrôle de configuration → null · forceTLS à l’exécution
app/Support/Realtime.php Filet de sécurité de la diffusion (sonde fsockopen de up() · absorbeur d’exceptions de fire())
routes/channels.php Callbacks d’autorisation de canal (actuellement seulement le App.Models.User.{id} par défaut)
app/Events/InfrRemoteEmulateTick.php Le seul événement de diffusion réellement utilisé
le contrôleur …/live de chaque écran + …Service::rev() charge utile en direct pour l’interrogation + jeton de changement

Realtime — défense à deux couches (le WS peut mourir sans emporter le travail d’origine)

// (1) up() — sonde fsockopen de 150 ms (mémoïsée par requête). Le broadcastWhen() d’un événement s’appuie dessus,
//     de sorte que, Reverb étant à l’arrêt, un événement ShouldBroadcastNow ne lève PAS d’exception en ligne sur un timeout de connexion.
public static function up(): bool  // sonde à partir de la configuration (aucune valeur en dur)

// (2) fire() — protège l’appelant même lorsque Reverb est en service mais refuse (413, ou 5xx pendant un redémarrage).
//     Les échecs sont remontés via report() vers Pulse Exceptions ; le travail d’origine (un résultat d’analyse enregistré) réussit malgré tout.
public static function fire(object $event): void

Le broadcastWhen() d’un événement renvoie Realtime::up() — si Reverb est arrêté, il ignore totalement l’envoi.


Accès

Autorisation des canaux

Type de canal Authentification
Canal public (infr.emulate.{runId}) aucune — le jeton de capacité runId constitue lui-même le droit d’accès (impossible à deviner)
canaux private / presence (feuille de route de conception) le callback de routes/channels.php vérifie le user_level de session + la portée du rôle

Le tableau des canaux temps réel de CLAUDE.md (private-infr.server.{id}, private-infr.threats, presence-infr.ops, …) est une feuille de route de conception. La diffusion réellement implémentée aujourd’hui se limite à l’unique canal public infr.emulate.{runId}, et routes/channels.php n’enregistre que le canal privé App.Models.User.{id} fourni par défaut par le framework. Lorsque des canaux private/presence seront ajoutés, autorisez toujours selon le user_level et la portée (p. ex. infr.threats exige user_level>=2 && scope∋security).

Accès aux points de terminaison d’interrogation

Les points de terminaison d’interrogation /{screen}/live héritent du contrôle de niveau de lecture du contrôleur de leur écran (demo=1, staff=5, admin=10 ; certaines zones sont protégées par le middleware infr.level:N). Par exemple, l’interrogation de repli sur l’état de l’émulation distante (emulate-status) requiert un accès en écriture (niveau ≥2). Voir Niveaux RBAC pour la politique complète.


Dépannage et FAQ

Q. Les WebSockets ne se connectent pas, mais l’écran continue de se mettre à jour ?

C’est le comportement attendu. Les écrans en direct sont pleinement fonctionnels en interrogation sans WS. Les WebSockets ne font que réduire la latence des tâches pilotées par événements, comme l’émulation distante.

Q. J’ai activé Reverb mais le navigateur ne se connecte pas

Q. Le tableau de bord sollicite-t-il trop le serveur / la base ?

Q. Puis-je planifier les daemons temps réel ?

Jamais. Ne lancez pas depuis le planificateur (Schedule::command(...)) des daemons à boucle infinie tels que reverb:start, queue:work ou pulse:check. Les processus qui ne se terminent jamais s’empilent à chaque tick et épuisent le pool de connexions MySQL partagé (mesuré le 2026-08-06 avec pulse:check : 169 accumulés en 16 heures → [1040] Too many connections, avec un impact sur la base de production). N’exécutez les daemons que depuis l’unique volet persistant du lanceur (développement) ou via supervisor/systemd (production). Voir Développement · Observabilité pour l’emplacement des daemons.

Q. Comment redémarrer Reverb après une modification de code ?

En production, php artisan reverb:restart sans interruption de service (ou redémarrez-le sous supervisor). En développement, redémarrez le volet du lanceur. Si le WS refuse brièvement les connexions pendant le redémarrage, Realtime::fire() absorbe l’exception et l’interrogation comble le vide.


Voir aussi

헤더의 LIVE 표시 — 화면이 스스로 갱신되는 중
헤더의 LIVE 표시 — 화면이 스스로 갱신되는 중