From e07ef9e68f2ca67cf9acb8a41499b95ff59402d9 Mon Sep 17 00:00:00 2001 From: jaxperro Date: Sat, 11 Jul 2026 02:04:21 -0400 Subject: [PATCH] =?UTF-8?q?rtds:=20silent-stale=20guard=20=E2=80=94=20forc?= =?UTF-8?q?e=20reconnect=20after=20120s=20without=20messages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2026-07-11 04:00Z: the socket sat 'up' delivering nothing for 35 min with no close event, so the on-close reconnect never fired (backstops covered detection). The ping thread now force-closes a 120s-silent stream to trigger the clean reconnect path. Co-Authored-By: Claude Fable 5 --- copybot.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/copybot.py b/copybot.py index d1c60946..7ea66837 100644 --- a/copybot.py +++ b/copybot.py @@ -513,6 +513,7 @@ class RtdsListener: def on_open(ws): ws.send(sub) self.state = "up" + self.last_msg = time.time() # fresh baseline for the stale check log("rtds: connected — activity/trades stream up (T0 detection)") def ping(): # app-level ping keeps RTDS alive @@ -522,6 +523,19 @@ class RtdsListener: ws.send('{"action":"ping"}') except Exception: break + # SILENT-STALE guard (2026-07-11 04:00Z: the socket sat + # "up" delivering nothing for 35 min — no close event, so + # the reconnect loop never fired; backstops covered). + # The platform firehose never goes quiet for 2 min even + # at 4am UTC — force-close to trigger a clean reconnect. + # A false trip is just a harmless retry. + if time.time() - self.last_msg > 120: + log("rtds: stream silent 120s — forcing reconnect") + try: + ws.close() + except Exception: + pass + break threading.Thread(target=ping, daemon=True).start() def on_message(ws, raw):