Files
oc-scheduler/docs/nats.md
2026-02-23 18:10:47 +01:00

5.8 KiB

NATS dans oc-scheduler

Vue d'ensemble

oc-scheduler utilise NATS comme bus d'événements pour deux objectifs :

  1. Recevoir les planners (disponibilité des ressources) publiés par oc-discovery.
  2. Réagir aux modifications de workflows pour diffuser un planner actualisé et signaler les streams WebSocket actifs.

Tout le code NATS se trouve dans infrastructure/nats.go.


Canaux écoutés

PROPALGATION_EVENT — réception des planners

Condition d'acceptation : resp.FromApp == "oc-discovery" et prop.Action == PB_PLANNER.

Ce qui se passe :

  • Le payload est désérialisé en planner.Planner.
  • Le champ peer_id est extrait pour identifier le pair.
  • Le planner est stocké dans PlannerCache[peerID] via storePlanner().
  • Si c'est la première apparition de ce peerID dans le cache, une goroutine de TTL est lancée (voir §TTL ci-dessous).
  • Tous les abonnés en attente d'un changement sur ce peerID sont notifiés.

CREATE_RESOURCE — modification d'un workflow

Condition d'acceptation : resp.Datatype == WORKFLOW.

Ce qui se passe :

  1. Le payload est désérialisé en workflow.Workflow.
  2. broadcastPlanner(wf) est appelé : pour chaque pair (storage + compute) du workflow dont le planner n'est pas encore en cache, un événement PB_PLANNER est émis sur NATS afin de demander un planner frais à oc-discovery.
  3. notifyWorkflowWatchers(wf.GetID()) est appelé : tous les streams WebSocket qui observent ce workflow sont signalés pour rafraîchir leur liste de pairs surveillés.

Canaux émis

PROPALGATION_EVENT — deux actions possibles

Action Déclencheur Effet attendu
PB_PLANNER Workflow modifié, pair inconnu du cache oc-discovery renvoie le planner du pair
PB_CLOSE_PLANNER TTL expiré ou déconnexion WebSocket Les consommateurs (oc-discovery, autres schedulers) libèrent leur état pour ce pair

Cache des planners (PlannerCache)

PlannerCache : map[string]*planner.Planner   // clé = peerID
plannerAddedAt : map[string]time.Time        // horodatage de première insertion
  • Protégé par plannerMu (RWMutex).
  • Alimenté uniquement via storePlanner() (appelé par le listener NATS).
  • Supprimé via EmitNATS(peerID, PB_CLOSE_PLANNER), qui efface l'entrée et notifie les abonnés.

TTL de 24 heures

À la première insertion d'un peerID, une goroutine est lancée :

sleep(24h)
→ si l'entrée existe encore : EmitNATS(peerID, PB_CLOSE_PLANNER)

Cela évite que des planners obsolètes stagnent indéfiniment. L'entrée est supprimée et les streams actifs reçoivent une notification « plus de planner » pour ce pair.


Pub/sub interne

Un registre d'abonnements en mémoire permet à d'autres composants (notamment le controller WebSocket) de réagir aux événements sans coupler directement le code NATS et les goroutines HTTP.

Deux registres distincts :

Registre Clé Signification
plannerSubs peerID « le planner de ce pair a changé »
workflowSubs workflowID « ce workflow a été modifié »

API

// S'abonner aux changements de planners pour plusieurs pairs
ch, cancel := SubscribePlannerUpdates(peerIDs []string)

// S'abonner aux modifications d'un workflow
ch, cancel := SubscribeWorkflowUpdates(wfID string)

Chaque canal est bufférisé (capacity 1) : si un signal est déjà en attente, les suivants sont ignorés sans bloquer.


Intégration avec le stream WebSocket (GET /oc/:id/check)

Le handler CheckStream dans controllers/workflow_sheduler.go exploite ces mécanismes :

  1. Ouverture : résolution des peerIDs du workflow, abonnement à SubscribePlannerUpdates et SubscribeWorkflowUpdates.
  2. Boucle de streaming :
    • plannerCh reçoit un signal → re-calcul du CheckResult et envoi au client.
    • wfCh reçoit un signal (workflow modifié) → recalcul des peerIDs, désabonnement + ré-abonnement aux nouveaux pairs, re-calcul et envoi.
  3. Fermeture (déconnexion client) :
    • Désabonnement des deux registres.
    • EmitNATS(peerID, PB_CLOSE_PLANNER) pour chaque pair surveillé : le cache est purgé et oc-discovery est informé que le scheduler n'a plus besoin du planner.

Flux de données résumé

oc-discovery ──PROPALGATION_EVENT(PB_PLANNER)──► ListenNATS
                                                      │
                                               storePlanner()
                                               PlannerCache[peerID] = planner
                                               notifyPlannerWatchers(peerID)
                                                      │
                                            SubscribePlannerUpdates
                                                      │
                                              CheckStream (WS) ──► client

Workflow modifié ──CREATE_RESOURCE(WORKFLOW)──► ListenNATS
                                                      │
                                           broadcastPlanner(wf)
                                           PROPALGATION_EVENT(PB_PLANNER) → oc-discovery
                                           notifyWorkflowWatchers(wfID)
                                                      │
                                            SubscribeWorkflowUpdates
                                                      │
                                        CheckStream refresh peerIDs ──► client

TTL 24h / déconnexion WS ──► EmitNATS(PB_CLOSE_PLANNER)
                                      │
                             delete PlannerCache[peerID]
                             notifyPlannerWatchers(peerID)
                             PROPALGATION_EVENT(PB_CLOSE_PLANNER) → NATS bus