From 310c1f52bdf37995e5c4c28ad81b742c9bd48b61 Mon Sep 17 00:00:00 2001 From: rufinomec-afk Date: Sun, 7 Jun 2026 23:06:57 -0300 Subject: [PATCH] fix: broadcast active cluster em todo tick live, heartbeat WS Remove guard closed_json que bloqueava updates do cluster ativo. Frontend recebe estado a cada tick sem precisar de F5. Heartbeat ping a cada 20s para manter conexao WS viva. Co-Authored-By: Claude Sonnet 4.6 --- backend/server.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/backend/server.py b/backend/server.py index 68dc6d6..40a72fc 100644 --- a/backend/server.py +++ b/backend/server.py @@ -25,11 +25,11 @@ collector_task: Optional[asyncio.Task] = None def broadcast_update(active_json: dict, closed_json: Optional[dict]): """ - Callback executed by MT5Collector when a new tick is processed. - Only broadcasts when a cluster closes (not every tick) to avoid flooding during replay. - Removes dead connections automatically. + Callback executed by MT5Collector on every live tick. + Always broadcasts the active cluster state so the frontend updates in real-time. + closed_json is None between cluster closes — frontend handles that gracefully. """ - if not active_connections or closed_json is None: + if not active_connections: return message = { "type": "tick", @@ -124,7 +124,6 @@ async def websocket_endpoint(websocket: WebSocket): active_connections.add(websocket) logger.info(f"Client connected. Active connections: {len(active_connections)}") - # Send the current active cluster state on connection try: await websocket.send_json({ "type": "init", @@ -133,6 +132,16 @@ async def websocket_endpoint(websocket: WebSocket): except Exception as e: logger.error(f"Error sending init state: {e}") + async def heartbeat(): + """Ping every 20s to keep the connection alive through proxies/browsers.""" + try: + while True: + await asyncio.sleep(20) + await websocket.send_json({"type": "ping"}) + except Exception: + pass + + ping_task = asyncio.create_task(heartbeat()) try: while True: await websocket.receive_text() @@ -142,6 +151,8 @@ async def websocket_endpoint(websocket: WebSocket): except Exception as e: logger.error(f"WebSocket error: {e}") active_connections.discard(websocket) + finally: + ping_task.cancel() if __name__ == "__main__": import uvicorn