Reduce websocket reconnect load
This commit is contained in:
44
app/main.py
44
app/main.py
@@ -117,7 +117,7 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
app = FastAPI(
|
||||
title="SillyHome Next API",
|
||||
description="Lokales Smart-Home-Intelligenzsystem für Home Assistant.",
|
||||
version="1.7.1",
|
||||
version="1.7.2",
|
||||
lifespan=lifespan,
|
||||
)
|
||||
app.state.settings = load_settings()
|
||||
@@ -255,6 +255,9 @@ async def _ha_event_listener(app: FastAPI, client: HaClient) -> None:
|
||||
ws_url = ha_url.replace("http://", "ws://").replace("https://", "wss://") + "/api/websocket"
|
||||
auth_token = cast(str, settings.ha_token)
|
||||
ws_status = getattr(app.state, "ws_status", None)
|
||||
reconnect_delay = 1.0
|
||||
relevant_entity_ids: set[str] = set()
|
||||
relevant_loaded_at = 0.0
|
||||
while True:
|
||||
if ws_status is not None:
|
||||
ws_status.status = "connecting"
|
||||
@@ -283,6 +286,9 @@ async def _ha_event_listener(app: FastAPI, client: HaClient) -> None:
|
||||
|
||||
logger.info("WebSocket-Verbindung zu Home Assistant hergestellt")
|
||||
state_cache = await asyncio.to_thread(_load_ha_state_cache, ha_reader)
|
||||
relevant_entity_ids = await asyncio.to_thread(_relevant_entity_ids, store)
|
||||
relevant_loaded_at = asyncio.get_running_loop().time()
|
||||
reconnect_delay = 1.0
|
||||
if ws_status is not None:
|
||||
ws_status.status = "connected"
|
||||
ws_status.error = None
|
||||
@@ -309,6 +315,12 @@ async def _ha_event_listener(app: FastAPI, client: HaClient) -> None:
|
||||
entity_id = event_data.get("entity_id")
|
||||
if not entity_id:
|
||||
continue
|
||||
loop_time = asyncio.get_running_loop().time()
|
||||
if loop_time - relevant_loaded_at >= 10:
|
||||
relevant_entity_ids = await asyncio.to_thread(_relevant_entity_ids, store)
|
||||
relevant_loaded_at = loop_time
|
||||
if entity_id not in relevant_entity_ids:
|
||||
continue
|
||||
new_state = event_data.get("new_state")
|
||||
_update_ha_state_cache(state_cache, entity_id, new_state)
|
||||
# Prüfe, ob Entity ein Aktor oder relevanter Kontext ist
|
||||
@@ -328,17 +340,24 @@ async def _ha_event_listener(app: FastAPI, client: HaClient) -> None:
|
||||
websockets.exceptions.InvalidStatus,
|
||||
OSError,
|
||||
) as exc:
|
||||
logger.warning("WebSocket-Verbindung unterbrochen: %s. Wiederholung in 1s...", exc)
|
||||
delay = reconnect_delay
|
||||
logger.warning(
|
||||
"WebSocket-Verbindung unterbrochen: %s. Wiederholung in %.0fs...",
|
||||
exc,
|
||||
delay,
|
||||
)
|
||||
if ws_status is not None:
|
||||
ws_status.status = "reconnecting"
|
||||
ws_status.error = str(exc)
|
||||
await asyncio.sleep(1)
|
||||
await asyncio.sleep(delay)
|
||||
reconnect_delay = min(reconnect_delay * 2, 60.0)
|
||||
except Exception as exc:
|
||||
logger.exception("Unerwarteter Fehler im Event-Listener: %s", exc)
|
||||
if ws_status is not None:
|
||||
ws_status.status = "error"
|
||||
ws_status.error = str(exc)
|
||||
await asyncio.sleep(1)
|
||||
await asyncio.sleep(reconnect_delay)
|
||||
reconnect_delay = min(reconnect_delay * 2, 60.0)
|
||||
|
||||
|
||||
# Fallback: periodische Vorhersage falls Event-Stream ausfällt
|
||||
@@ -353,7 +372,7 @@ async def _fallback_prediction(app: FastAPI) -> None:
|
||||
await asyncio.sleep(
|
||||
app.state.settings.prediction_interval_seconds
|
||||
if websocket_connected
|
||||
else min(5, app.state.settings.prediction_interval_seconds)
|
||||
else max(30, app.state.settings.prediction_interval_seconds)
|
||||
)
|
||||
# Nur ausführen, wenn WebSocket nicht verbunden ist
|
||||
ws_status = getattr(app.state, "ws_status", None)
|
||||
@@ -389,15 +408,14 @@ def _update_ha_state_cache(
|
||||
)
|
||||
|
||||
|
||||
def _is_relevant_state_change(store: ActuatorStore, entity_id: str) -> bool:
|
||||
def _relevant_entity_ids(store: ActuatorStore) -> set[str]:
|
||||
result: set[str] = set()
|
||||
for record in store.list():
|
||||
if record.actuator_entity_id == entity_id:
|
||||
return True
|
||||
if record.assignment.selected_numeric_entity_id == entity_id:
|
||||
return True
|
||||
if entity_id in record.assignment.selected_context_entity_ids:
|
||||
return True
|
||||
return False
|
||||
result.add(record.actuator_entity_id)
|
||||
if record.assignment.selected_numeric_entity_id:
|
||||
result.add(record.assignment.selected_numeric_entity_id)
|
||||
result.update(record.assignment.selected_context_entity_ids)
|
||||
return result
|
||||
|
||||
|
||||
def _ha_entity_from_event(
|
||||
|
||||
Reference in New Issue
Block a user