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 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6fe8920412
commit
310c1f52bd
+16
-5
@@ -25,11 +25,11 @@ collector_task: Optional[asyncio.Task] = None
|
|||||||
|
|
||||||
def broadcast_update(active_json: dict, closed_json: Optional[dict]):
|
def broadcast_update(active_json: dict, closed_json: Optional[dict]):
|
||||||
"""
|
"""
|
||||||
Callback executed by MT5Collector when a new tick is processed.
|
Callback executed by MT5Collector on every live tick.
|
||||||
Only broadcasts when a cluster closes (not every tick) to avoid flooding during replay.
|
Always broadcasts the active cluster state so the frontend updates in real-time.
|
||||||
Removes dead connections automatically.
|
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
|
return
|
||||||
message = {
|
message = {
|
||||||
"type": "tick",
|
"type": "tick",
|
||||||
@@ -124,7 +124,6 @@ async def websocket_endpoint(websocket: WebSocket):
|
|||||||
active_connections.add(websocket)
|
active_connections.add(websocket)
|
||||||
logger.info(f"Client connected. Active connections: {len(active_connections)}")
|
logger.info(f"Client connected. Active connections: {len(active_connections)}")
|
||||||
|
|
||||||
# Send the current active cluster state on connection
|
|
||||||
try:
|
try:
|
||||||
await websocket.send_json({
|
await websocket.send_json({
|
||||||
"type": "init",
|
"type": "init",
|
||||||
@@ -133,6 +132,16 @@ async def websocket_endpoint(websocket: WebSocket):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error sending init state: {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:
|
try:
|
||||||
while True:
|
while True:
|
||||||
await websocket.receive_text()
|
await websocket.receive_text()
|
||||||
@@ -142,6 +151,8 @@ async def websocket_endpoint(websocket: WebSocket):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"WebSocket error: {e}")
|
logger.error(f"WebSocket error: {e}")
|
||||||
active_connections.discard(websocket)
|
active_connections.discard(websocket)
|
||||||
|
finally:
|
||||||
|
ping_task.cancel()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|||||||
Reference in New Issue
Block a user