mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-17 04:10:04 +02:00
Démarrage, captures, postes distants : correctifs portés d'AJEAN
- Au démarrage, une lecture ratée de la base (verrou bbolt transitoire pendant le chevauchement des process au redémarrage du conteneur) était confondue avec une conversation absente. Pire que l'amont chez nous : getStr rend "" dans les deux cas, donc convEnsureActive forgeait un NOUVEL identifiant et l'écrasait — le fil en cours devenait orphelin, en silence. On sonde désormais la base avec son erreur AVANT toute écriture, on réessaie quatre fois, et un échec durable est journalisé sans que rien ne soit touché. - Une capture d'écran disparaissait sans laisser de trace : stripImageParts aplatissait le message en ne gardant que sa légende. Le marqueur imageLostMarker rend la perte VISIBLE, pour que le modèle sache reprendre une capture au lieu de la redécrire de mémoire. - maxLogEvents 20000 → 200000 : un seul tour à très long raisonnement tronquait déjà le journal de rejeu, et l'utilisateur perdait le début de sa conversation à l'écran. - Keepalive WebSocket des postes distants (ping toutes les 25 s, des DEUX côtés). Sans lui, un poste au repos était coupé au bout de ~60-100 s par les intermédiaires qui ferment les canaux inactifs, puis reconnecté après backoff — les déconnexions à répétition sur tous les postes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2d4f5378c0
commit
c45ba615fa
6 files changed
+308
-11
No files matched your search
@@ -25,6 +25,12 @@ const (
|
||||
nodePairCodeTTL = 10 * time.Minute
|
||||
nodeCallTimeout = 5 * time.Minute // un shell distant peut être long
|
||||
nodeHelloWait = 15 * time.Second
|
||||
// nodePingInterval : cadence du keepalive WebSocket poste↔serveur. 25 s tient
|
||||
// sous les délais d'inactivité usuels des proxys et relais (~60-100 s).
|
||||
nodePingInterval = 25 * time.Second
|
||||
// nodePingTimeout : au-delà, le poste ne répond plus — on ferme au lieu de
|
||||
// laisser une connexion morte occuper le registre.
|
||||
nodePingTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
// pairedNode est un poste appairé, tel que persisté dans bkState["nodes"].
|
||||
@@ -279,6 +285,34 @@ func handleNodeWS(w http.ResponseWriter, r *http.Request) {
|
||||
defer nodeUnregister(nc)
|
||||
touchNodeSeen(pn.ID)
|
||||
|
||||
// Keepalive : un ping WebSocket périodique garde la connexion vivante à travers
|
||||
// les intermédiaires qui coupent les canaux INACTIFS (relais, Caddy, Cloudflare :
|
||||
// ~60-100 s sans trafic). Sans lui, un poste au repos — l'IA ne le sollicite pas
|
||||
// en permanence — était déconnecté en boucle puis reconnecté après backoff.
|
||||
// coder/websocket sérialise Ping avec les écritures de données en interne : pas
|
||||
// de course avec nc.send. Un ping sans réponse ferme la connexion, ce qui
|
||||
// débloque le Read de la boucle ci-dessous.
|
||||
pingCtx, stopPing := context.WithCancel(ctx)
|
||||
defer stopPing()
|
||||
go func() {
|
||||
t := time.NewTicker(nodePingInterval)
|
||||
defer t.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-pingCtx.Done():
|
||||
return
|
||||
case <-t.C:
|
||||
pc, cancel := context.WithTimeout(pingCtx, nodePingTimeout)
|
||||
err := c.Ping(pc)
|
||||
cancel()
|
||||
if err != nil {
|
||||
_ = c.Close(websocket.StatusGoingAway, "ping sans réponse")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Boucle de lecture : des « result » chiffrés qui débloquent l'appel en attente.
|
||||
for {
|
||||
m, err := nc.readMsg(ctx)
|
||||
|
||||
Reference in new issue
Block a user