Deine Verbindung lebt, aber niemand ist zu Hause: Wie Hermes-Heartbeats stille Verbindungsabbrüche heilen

Du klappst dein Laptop zu, gehst Mittag essen und kommst zurück — Hermes steht immer noch auf dem Bildschirm: Sitzungsverlauf, Cursor, alles sieht völlig normal aus. Du tippst eine Nachricht und drückst Enter, doch nichts passiert: kein Fehler, kein Spinner, kein Timeout, nur Stille. Deine Nachricht ist in einem schwarzen Loch verschwunden.
Dieses „Interface lebt, Verbindung tot“-Szenario nennt man einen silent disconnect. Es ist keine Hermes-Eigenheit — es ist eine Krankheit, von der jedes vernetzte Programm betroffen ist: Das Netzwerk ist weg, aber keine der beiden Seiten weiß davon, also wartet die eine Seite, und die andere wartet ebenfalls. Eine Reihe kürzlich in Hermes gemergter Änderungen lässt TUI und Desktop diese Zombie-Verbindungen erkennen und von selbst wieder aufbauen. Hier erfährst du, was sie tatsächlich repariert haben und warum das für alle wichtig ist, die Hermes remote betreiben.
Warum Verbindungen ihren eigenen Tod vortäuschen
Zunächst die Grundlagen: Deine Hermes-Oberfläche — das Terminal-TUI oder die Desktop-App — spricht über eine einzige WebSocket-Verbindung mit dem eigentlichen „Gehirn“: dem Gateway-Prozess, der auf einem Server oder im Hintergrund deines Rechners läuft. Jede Nachricht, die du sendest, und jedes Token, das als Antwort zurückkommt, wandert durch diese Leitung.
Das Problem liegt im Netzwerk darunter. Angenommen, dein Mac schläft zehn Minuten, das Wi-Fi bricht zwischendurch ab, und er wacht mit einer neuen IP auf. Oder du wechselst vom Büro-Wi-Fi zum Hotspot deines Handys. Oder dein VPN baut sich neu auf. In all diesen Fällen existiert die alte TCP-Verbindung nicht mehr — aber dein Rechner weiß davon nichts. Der Fachbegriff dafür lautet half-open connection: Das eine Ende der Leitung ist verschwunden, das andere Ende glaubt weiterhin, alles sei in Ordnung.
Warum merkt keine der beiden Seiten etwas? TCP hat zwar einen Keepalive-Mechanismus, aber standardmäßig stößt er die Leitung viel zu selten an, um eine Rolle zu spielen, und Browser legen WebSocket-Entwicklern nicht einmal Ping/Pong offen. Der Client schreibt also weiterhin in eine tote Verbindung — Schreibvorgänge, die nicht laut scheitern, sondern einfach still ins Leere laufen. Genau dort verschwindet deine Nachricht im schwarzen Loch.
Die Lösung: ein dreischichtiger Heartbeat
PR #93792, gemergt am 24. August (er integriert drei Beiträge des Community-Entwicklers @100yenadmin — #89958, #90012, #89984), geht genau dieses Problem an: Jede Client-Verbindung pingt das Gateway jetzt nach einem festen Zeitplan an, erklärt die Verbindung für tot, wenn keine Antwort eintrifft, und baut sie automatisch wieder auf. Das Ganze arbeitet in drei Ebenen, von denen jede genau ein Problem löst.
Ebene 1: Der Server lernt, auf Pings zu antworten
Auf der Serverseite (tui_gateway/ws.py) passieren drei kleine Dinge. Erstens: Der Start-Handshake (gateway.ready) enthält nun heartbeat: true und teilt den Clients damit mit: „Ich unterstütze Heartbeats.“ Zweitens: Es kommt eine gateway.ping-Methode hinzu, die direkt in der Read-Schleife beantwortet wird — kein Queueing, kein Scheduling, Antwort direkt beim Eintreffen. Drittens: Jede Verbindung erhält einen last_inbound_at-Stempel (den Zeitpunkt, zu dem zuletzt Daten eintrafen), was spätere Diagnosen erleichtert.
Ebene 2: Der Client pingt nach Plan und erklärt die Verbindung bei Timeout für tot
Der TUI-Client (ui-tui/src/gatewayClient.ts) und der gemeinsame JsonRpcGatewayClient des Desktops verwenden dieselben Parameter: alle 15 Sekunden ein gateway.ping senden; trifft innerhalb von 45 Sekunden gar nichts mehr vom Gateway ein (nicht nur Heartbeat-Bestätigungen — jegliche Daten zählen), gilt die Verbindung als tot und wird für einen Reconnect abgerissen.
Warum 45 Sekunden und nicht 15? Netzwerk-Roundtrips haben Latenz, und ein einzelner verlorener Heartbeat bedeutet noch nicht, dass die Verbindung weg ist. Wenn du 45 Sekunden lang (drei Heartbeat-Zyklen) gar nichts gehört hast, ist das mit ziemlicher Sicherheit kein Jitter — die Verbindung ist wirklich tot.
Ebene 3: Exponential Backoff und das Verwerfen veralteter Daten
Sobald eine Verbindung für tot erklärt wurde, bombardiert der Client den Server nicht mit Reconnect-Versuchen. Er nutzt exponential backoff: Nach 1 Sekunde erneut versuchen, dann nach 2, dann 4, 8, 16 … mit einem Cap bei 30 Sekunden — und so lange weitermachen, bis die Verbindung steht. Jeder Versuch veröffentlicht ein gateway.reconnecting-Event (Versuchnummer + Verzögerung in Millisekunden), was die Fehlersuche erheblich erleichtert.
Der Desktop ergänzt einen feineren Mechanismus: socket generation invalidation. Beim Wiederaufbau der Verbindung erhält der neue Socket ein frisches Generation-Token; verspätete Frames, die auf dem alten Socket eintreffen — etwa die letzten Nachrichten, die der Gateway kurz vor dem Abbruch ausgesendet hat — werden verworfen, weil sie das alte Token tragen. Die neue Verbindung startet sauber, sodass Restverkehr eines toten Sockets die neue Sitzung nicht verunreinigen kann und keine Arbeit doppelt ausgeführt wird.
Ältere Gateways bleiben unberührt
Der gesamte Heartbeat ist capability-gated: Clients beginnen erst dann mit Heartbeats, wenn sie im gateway.ready-Handshake heartbeat: true empfangen haben. Wenn du weiterhin mit einem älteren Gateway verbunden bist — etwa einem Remote-Server, der noch nicht aktualisiert wurde — verhält sich der Client exakt wie zuvor. Das heißt: Dieser Fix kann zusammen mit neuen Clients ausgeliefert werden, ohne alte Server zu brechen.
Welche Szenarien abgedeckt sind
- Sleep/Wake: macOS- und Windows-Schlafzyklen bauen den Netzwerkstack neu auf — die häufigste Quelle für Zombie-Verbindungen. Früher führte der Desktop beim Aufwachen nur eine einmalige Sonde aus (das war #93694, am selben Tag früher gemergt; sie verhinderte, dass Remote-Gateway-Updates die App auf einem toten Socket stranden ließen). Jetzt liegt darunter ein kontinuierlicher Heartbeat.
- Netzwerkwechsel: Wechsel vom Wi-Fi zum Hotspot, Ethernet abziehen und wieder einstecken, Roaming im Büro.
- VPN-Reconnects: Wenn der Tunnel neu aufgebaut wird, sind alle TCP-Pakete der alten Verbindung verloren.
- Stille Server-Neustarts: Der Gateway-Prozess startet neu, aber der Client bekommt nie eine Close-Meldung.
Der Server hat außerdem TCP-Keepalive auf den WebSocket-Sockets aktiviert (Erkennung toter Gegenstellen) als zweite Verteidigungslinie.
Wann du das tatsächlich bekommst
Um beim Stand der Dinge ehrlich zu sein: Diese Änderungen leben nur auf main — sie sind in keiner getaggten Version ausgeliefert (die neueste, v0.20.5, wurde am 19. August getaggt, bevor dieser Schwung landete). Wenn du also heute hermes update ausführst, wirst du noch keine Heartbeat-Logs sehen. Upgrade, sobald die nächste Version erscheint — unser install and upgrade guide zeigt, wie es geht, und in den v0.20.5 release notes kannst du nachlesen, was die vorherige Version geändert hat.
Wie bestätigst du nach dem Upgrade, dass der Heartbeat funktioniert? Achte auf [lifecycle]-Zeilen im TUI: Im Normalbetrieb bleiben sie still; stolpert das Netzwerk, siehst du websocket silent drop detected; forcing reconnect und scheduling gateway reconnect in Xms. Das ist keine schlechte Nachricht mehr — es ist der Client, der sich selbst rettet.
Und falls dich die andere Art von Stillstand beschäftigt — eine hängende Reasoning-Schleife des Agents (kein Verbindungsproblem, sondern der Agent selbst, der seine Arbeit einstellt) — das ist ein separater Mechanismus: der Loop-Watchdog auf Gateway-Seite, den wir im the loop-watchdog tuning guide behandelt haben. Lies beide zusammen, und du hast die Zuverlässigkeit sowohl auf Transport- als auch auf Ausführungsebene abgedeckt.
Zusammenfassung
Silent Disconnects sind der unsichtbare Killer von Remote-Tooling: kein Fehler, kein Hinweis, nur dein verdutzter Blick. Hermes’ Lösung ist im Kern erfrischend einfach — ping nach Plan, Reconnect, wenn niemand antwortet, und dabei höflicher Backoff — aber genau diese Einfachheit ist der Grund, warum sie funktioniert. Sie verwandelt „die Verbindung hat ihren Tod vorgetäuscht“ von einer Legende in ein erkennbares, behebbares Ereignis. Wenn dein Netzwerk das nächste Mal stolpert, hör auf, ins schwarze Loch zu starren: Der Client arbeitet bereits an einem Weg zurück.