make listener robust to bad data

This commit is contained in:
2025-09-05 08:47:31 +00:00
parent 76629b8e30
commit 4c44b98d53
8 changed files with 1437 additions and 216 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,13 @@
"commitId": "a1b2c3d4e5f6" "commitId": "a1b2c3d4e5f6"
}, },
"changelog": [ "changelog": [
{
"version": "2025.1.0-alpha.4",
"date": "2025-09-01",
"changes": [
"Grundstruktur für Deployment getestet und optimiert."
]
},
{ {
"version": "2025.1.0-alpha.3", "version": "2025.1.0-alpha.3",
"date": "2025-08-30", "date": "2025-08-30",

View File

@@ -123,21 +123,18 @@ services:
- infoscreen-net - infoscreen-net
scheduler: scheduler:
image: ghcr.io/robbstarkaustria/infoscreen-scheduler:latest # Oder wo auch immer Ihre Images liegen image: ghcr.io/robbstarkaustria/infoscreen-scheduler:latest
container_name: infoscreen-scheduler container_name: infoscreen-scheduler
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
# HINZUGEFÜGT: Stellt sicher, dass die DB vor dem Scheduler startet
db: db:
condition: service_healthy condition: service_healthy
mqtt: mqtt:
condition: service_healthy condition: service_healthy
environment: environment:
# HINZUGEFÜGT: Datenbank-Verbindungsstring
DB_CONN: "mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}" DB_CONN: "mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}"
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
DB_NAME: ${DB_NAME}
DB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MQTT_BROKER_URL: mqtt
MQTT_PORT: 1883 MQTT_PORT: 1883
networks: networks:
- infoscreen-net - infoscreen-net

View File

@@ -5,8 +5,8 @@ networks:
services: services:
listener: listener:
build: build:
context: ./listener context: .
dockerfile: Dockerfile dockerfile: listener/Dockerfile
image: infoscreen-listener:latest image: infoscreen-listener:latest
container_name: infoscreen-listener container_name: infoscreen-listener
restart: unless-stopped restart: unless-stopped
@@ -16,6 +16,7 @@ services:
mqtt: mqtt:
condition: service_healthy condition: service_healthy
environment: environment:
- DB_CONN=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}
- DB_URL=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME} - DB_URL=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}
# 🔧 ENTFERNT: Volume-Mount ist nur für die Entwicklung # 🔧 ENTFERNT: Volume-Mount ist nur für die Entwicklung
networks: networks:
@@ -80,8 +81,8 @@ services:
server: server:
build: build:
context: ./server context: .
dockerfile: Dockerfile dockerfile: server/Dockerfile
image: infoscreen-api:latest image: infoscreen-api:latest
container_name: infoscreen-api container_name: infoscreen-api
restart: unless-stopped restart: unless-stopped
@@ -111,8 +112,8 @@ services:
# ✅ GEÄNDERT: Dashboard jetzt mit Node.js/React statt Python/Dash # ✅ GEÄNDERT: Dashboard jetzt mit Node.js/React statt Python/Dash
dashboard: dashboard:
build: build:
context: ./dashboard context: .
dockerfile: Dockerfile dockerfile: dashboard/Dockerfile
# 🔧 VEREINFACHT: Build-Args werden durch Umgebungsvariablen gesetzt # 🔧 VEREINFACHT: Build-Args werden durch Umgebungsvariablen gesetzt
args: args:
- VITE_API_URL=${API_URL} - VITE_API_URL=${API_URL}
@@ -140,22 +141,23 @@ services:
scheduler: scheduler:
build: build:
context: ./scheduler dockerfile: scheduler/Dockerfile
dockerfile: Dockerfile
image: infoscreen-scheduler:latest image: infoscreen-scheduler:latest
container_name: infoscreen-scheduler container_name: infoscreen-scheduler
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
# HINZUGEFÜGT: Stellt sicher, dass die DB vor dem Scheduler startet
db: db:
condition: service_healthy condition: service_healthy
mqtt: mqtt:
condition: service_healthy condition: service_healthy
environment: environment:
DB_CONN: "mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}" # HINZUGEFÜGT: Datenbank-Verbindungsstring
MQTT_BROKER_URL: mqtt - DB_CONN=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME}
MQTT_PORT: 1883 - MQTT_PORT=1883
networks: networks:
- infoscreen-net - infoscreen-net
volumes: volumes:
server-pip-cache:
db-data: db-data:

View File

@@ -50,12 +50,13 @@ def on_message(client, userdata, msg):
# Discovery-Handling # Discovery-Handling
payload = json.loads(msg.payload.decode()) payload = json.loads(msg.payload.decode())
logging.info(f"Discovery empfangen: {payload}") logging.info(f"Discovery empfangen: {payload}")
if "uuid" in payload:
uuid = payload["uuid"]
session = Session() session = Session()
existing = session.query(Client).filter_by( existing = session.query(Client).filter_by(uuid=uuid).first()
uuid=payload["uuid"]).first()
if not existing: if not existing:
new_client = Client( new_client = Client(
uuid=payload.get("uuid"), uuid=uuid,
hardware_token=payload.get("hardware_token"), hardware_token=payload.get("hardware_token"),
ip=payload.get("ip"), ip=payload.get("ip"),
type=payload.get("type"), type=payload.get("type"),
@@ -68,14 +69,16 @@ def on_message(client, userdata, msg):
) )
session.add(new_client) session.add(new_client)
session.commit() session.commit()
logging.info(f"Neuer Client registriert: {payload['uuid']}") logging.info(f"Neuer Client registriert: {uuid}")
else: else:
logging.info(f"Client bereits bekannt: {payload['uuid']}") logging.info(f"Client bereits bekannt: {uuid}")
session.close() session.close()
# Discovery-ACK senden # Discovery-ACK senden
ack_topic = f"infoscreen/{payload['uuid']}/discovery_ack" ack_topic = f"infoscreen/{uuid}/discovery_ack"
client.publish(ack_topic, json.dumps({"status": "ok"})) client.publish(ack_topic, json.dumps({"status": "ok"}))
logging.info(f"Discovery-ACK gesendet an {ack_topic}") logging.info(f"Discovery-ACK gesendet an {ack_topic}")
else:
logging.warning("Discovery ohne UUID empfangen, ignoriert.")
except Exception as e: except Exception as e:
logging.error(f"Fehler bei Verarbeitung: {e}") logging.error(f"Fehler bei Verarbeitung: {e}")

View File

@@ -5,4 +5,4 @@ RUN pip install --no-cache-dir -r requirements.txt
COPY scheduler/ ./scheduler COPY scheduler/ ./scheduler
COPY models/ ./models COPY models/ ./models
ENV PYTHONPATH=/app ENV PYTHONPATH=/app
CMD ["python", "scheduler/scheduler.py"] CMD ["python", "-m", "scheduler.scheduler"]

View File

@@ -2,7 +2,7 @@
import os import os
import logging import logging
from db_utils import get_active_events from .db_utils import get_active_events
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
import json import json
import datetime import datetime

View File

@@ -20,16 +20,16 @@ ENV LANG=de_DE.UTF-8 \
LC_ALL=de_DE.UTF-8 LC_ALL=de_DE.UTF-8
# Setze das Arbeitsverzeichnis auf den Workspace-Root, passend zu den Mounts. # Setze das Arbeitsverzeichnis auf den Workspace-Root, passend zu den Mounts.
WORKDIR /workspace WORKDIR /app
# Kopiere die Anforderungsdateien in das korrekte Unterverzeichnis. # Kopiere die Anforderungsdateien in das korrekte Unterverzeichnis.
# ✅ KORRIGIERT: Pfade sind jetzt relativ zum Build-Kontext (dem 'server'-Verzeichnis) # ✅ KORRIGIERT: Pfade sind jetzt relativ zum Build-Kontext (dem 'server'-Verzeichnis)
COPY requirements.txt requirements-dev.txt ./ COPY server/requirements.txt server/requirements-dev.txt ./server/
# Installiere die Python-Abhängigkeiten # Installiere die Python-Abhängigkeiten
RUN pip install --upgrade pip \ RUN pip install --upgrade pip \
&& pip install --no-cache-dir -r requirements.txt \ && pip install --no-cache-dir -r server/requirements.txt \
&& pip install --no-cache-dir -r requirements-dev.txt && pip install --no-cache-dir -r server/requirements-dev.txt
# Das Kopieren des Codes ist nicht nötig, da das Verzeichnis gemountet wird. # Das Kopieren des Codes ist nicht nötig, da das Verzeichnis gemountet wird.