sequenceDiagram title Native Indexer — Boucles background (offload, DHT refresh, GC streams) participant IndexerA as Indexer A (enregistré) participant IndexerB as Indexer B (enregistré) participant Native as Native Indexer participant DHT as DHT Kademlia participant NodeA as Node A (responsible peer) Note over Native: runOffloadLoop — toutes les 30s loop Toutes les 30s Native->>Native: len(responsiblePeers) > 0 ? Note over Native: responsiblePeers = peers pour lesquels
le native a fait selfDelegate (aucun indexer dispo) alt Des responsible peers existent (ex: Node A) Native->>Native: reachableLiveIndexers() Note over Native: Filtre liveIndexers par TTL
ping PeerIsAlive pour chaque candidat alt Indexers A et B maintenant joignables Native->>Native: responsiblePeers = {} (libère Node A et autres) Note over Native: Node A se reconnectera
au prochain ConnectToNatives else Toujours aucun indexer Note over Native: Node A reste sous la responsabilité du native end end end Note over Native: refreshIndexersFromDHT — toutes les 30s loop Toutes les 30s Native->>Native: Collecter tous les knownPeerIDs
= {PeerID_A, PeerID_B, ...} loop Pour chaque PeerID connu Native->>Native: liveIndexers[PeerID] encore frais ? alt Entrée manquante ou expirée Native->>DHT: SearchValue(ctx 5s, "/indexer/"+PeerID) DHT-->>Native: channel de bytes loop Pour chaque résultat DHT Native->>Native: Unmarshal → liveIndexerEntry Native->>Native: Garder le meilleur (ExpiresAt le plus récent, valide) end Native->>Native: liveIndexers[PeerID] = best entry Note over Native: "native: refreshed indexer from DHT" end end end Note over Native: LongLivedStreamRecordedService GC — toutes les 30s loop Toutes les 30s Native->>Native: gc() — lock StreamRecords[Heartbeat] loop Pour chaque StreamRecord (Indexer A, B, ...) Native->>Native: now > rec.Expiry ?
OU timeSince(LastSeen) > 2×TTL restant ? alt Pair périmé (ex: Indexer B disparu) Native->>Native: Supprimer Indexer B de TOUS les maps de protocoles Note over Native: Stream heartbeat fermé
liveIndexers[PeerID_B] expirera naturellement end end end Note over IndexerA: Indexer A continue à heartbeater normalement
et reste dans StreamRecords + liveIndexers