From 8674bca2d80c99adb9e14c7f04251867fbe0af81 Mon Sep 17 00:00:00 2001 From: arcattack Date: Tue, 14 Jul 2026 09:30:47 -0500 Subject: [PATCH] btconsole: survive socket errors + flush output (the mid-session sync-freeze lead) The console emulator's recv loop only caught socket.timeout -- any reset/abort killed the thread UNHANDLED, its buffered stdout died with it, and with both threads gone the process exited silently. The 2-node session then froze replication BOTH ways (each pod holding a dead ConsoleHost socket; the engine never logged a console disconnect). Now: OSErrors are caught + logged and the thread idles alive; prints flush. Run with python -u and > console.log to capture the death reason on any recurrence. The engine- side question (why a dead console freezes peer replication + the disconnect handler's gameListenerSocket-vs-consoleListenerSocket close) is logged in open-questions. Co-Authored-By: Claude Fable 5 --- tools/btconsole.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/btconsole.py b/tools/btconsole.py index bdeb29c..55cc238 100644 --- a/tools/btconsole.py +++ b/tools/btconsole.py @@ -122,7 +122,7 @@ def serve_pod(hostport, egg_bytes): try: data = s.recv(4096) if not data: - print(f"[{name}] pod closed the console socket") + print(f"[{name}] pod closed the console socket", flush=True) return # Expect the AcknowledgeEggFile (and possibly other console traffic). if len(data) >= 24: @@ -134,6 +134,14 @@ def serve_pod(hostport, egg_bytes): print(f"[{name}] pod->console {len(data)} bytes") except socket.timeout: continue + except OSError as e: + # Previously UNHANDLED: a reset/abort here killed the thread silently + # (buffered stdout lost) and the console process exited -- leaving the + # pods holding dead console sockets. Log it and keep the thread alive + # (idle) so the process + diagnosis survive. + print(f"[{name}] console socket error: {e!r} -- idling", flush=True) + while True: + time.sleep(60) def main():