Direkt zum Hauptinhalt

Betrieb und Wartung

Dieser Abschnitt beschreibt den laufenden Betrieb und die Wartung des MesoWorkerService.

Manuelles Datenbank-Update (optional)

Das manuelle Datenbank-Update ist nur in Sonderfällen erforderlich, z.B. wenn Sie die Datenbank explizit aktualisieren möchten, ohne den Service zu starten.

Windows:

MesoWorker.Win.exe -updateDatabase -silent

Container:

docker run --rm \
  -e ConnectionStrings__ConnectionString="Data Source=SQL-SERVER;Initial Catalog=MesoWorkerDb;User ID=sql-user;Password=***;TrustServerCertificate=true" \
  -e ConnectionStrings__WinLineSystemDBConnectionString="Data Source=SQL-SERVER;Initial Catalog=CWLSYSTEM;User ID=sql-user;Password=***;TrustServerCertificate=true" \
  ghcr.io/css-edv-support/mesoworkerservice-blazor:latest \
  -updateDatabase -forceUpdate -silent

Parameter:

  • -updateDatabase - Startet den Datenbankaktualisierungsmodus
  • -forceUpdate - Erzwingt Update auch wenn Versionen übereinstimmen (optional)
  • -silent - Keine Benutzerinteraktion erforderlich (optional)

Exit Codes: 0 = Erfolgreich, 1 = Fehler, 2 = Update nicht erforderlich

Mail-Journal

Das Mail-Journal protokolliert alle versendeten und fehlgeschlagenen E-Mails.

Zugriff: Navigieren Sie in der Administrationsoberfläche zu "Queued Mail" oder "Mail Journal".

Informationen im Journal:

  • Zeitstempel des Versands/Fehlers
  • Empfänger (To, CC, BCC)
  • Betreff
  • Status (versendet, fehlgeschlagen, wartend)
  • Fehlermeldungen (bei fehlgeschlagenen E-Mails)
  • Verknüpfter Workflow

Verwendung:

  • Überprüfen Sie regelmäßig das Journal auf fehlgeschlagene E-Mails
  • Analysieren Sie Fehlermeldungen bei Problemen
  • Überwachen Sie die Zustellungsrate

Fehlerbenachrichtigungen

Der Service benachrichtigt Administratoren automatisch bei Problemen.

Benachrichtigungsfälle:

  • E-Mail konnte nicht versendet werden
  • SMTP-Server ist nicht erreichbar
  • Authentifizierung fehlgeschlagen
  • Lizenz ist ungültig oder abgelaufen

Protokollierung

Der Service erstellt detaillierte Protokolldateien für Diagnose und Überwachung.

Protokolldateien:

  • Windows-Dienst: logs/MESOWorkerService-[Datum].txt im Programmverzeichnis (bei bestehenden Installationen heißt der Ordner noch Logs, unter Windows ist das gleichbedeutend)
  • Container: zweifach – die Konsolenausgabe landet im Docker-Log (docker logs mesoworkerservice, in Portainer unter Logs), zusätzlich schreibt der Worker dieselben Meldungen als Dateien nach /app/logs. Die Web-UI schreibt nur ins Docker-Log

Obergrenzen (NEU): Beide Wege sind ab dieser Version begrenzt, damit kein Datenträger mehr vollläuft:

Weg Standardgrenze Wo einstellbar
Protokolldateien des Workers 14 Dateien × 50 MB = max. 700 MB; täglich neue Datei, bei 50 MB wird zusätzlich gerollt Serilog:WriteTo:1:Args in appsettings.json bzw. Serilog__WriteTo__1__Args__* als Umgebungsvariable
Docker-Log je Container 3 × 10 MB = max. 30 MB logging:-Block im Stack (siehe Stack-Vorlage)

Ältere Installationen hatten diese Grenzen nicht: Docker rotiert den Standardtreiber json-file von sich aus nicht, und die Protokolldateien behielten bis zu 31 Tage mit je bis zu 1 GB. Prüfen Sie bei bestehenden Stacks, ob der logging:-Block vorhanden ist, und ergänzen Sie ihn gegebenenfalls. Als Rückfallnetz für alle Container eines Hosts kann die Rotation auch global in /etc/docker/daemon.json gesetzt werden (siehe Ressourcenempfehlung); sie gilt dann für neu erstellte Container.

Hinweis für Container: Im Container muss der Dateipfad /app/logs/… lauten (Kleinschreibung), weil Linux zwischen logs und Logs unterscheidet. Ein abweichender Pfad schreibt in die Container-Schicht statt ins Volume oder scheitert stillschweigend an fehlenden Schreibrechten.

Protokollierungsstufen:

  • Information: Normale Betriebsmeldungen
  • Warning: Warnungen (z.B. fehlende Empfänger)
  • Error: Fehler (z.B. Datenbankverbindung fehlgeschlagen)
  • Debug: Detaillierte Debug-Informationen (nur für Fehlersuche)

Konfiguration: Der Worker protokolliert über Serilog. Die Stufen stehen deshalb im Abschnitt Serilog:MinimumLevel der appsettings.json, nicht unter Logging:LogLevel – Einträge dort haben für den Worker keine Wirkung:

"Serilog": {
  "MinimumLevel": {
    "Default": "Information",
    "Override": {
      "Microsoft": "Information",
      "Microsoft.AspNetCore": "Warning",
      "System": "Warning"
    }
  }
}

Als Umgebungsvariable im Stack: Serilog__MinimumLevel__Default=Information, Serilog__MinimumLevel__Override__Quartz=Warning usw. Die Stufe Microsoft.AspNetCore steht standardmäßig auf Warning, damit die regelmäßigen Health-Check-Aufrufe das Protokoll nicht füllen.

Die Web-UI verwendet dagegen den Abschnitt Logging:LogLevel (bzw. Logging__LogLevel__*).

Best Practices:

  • Überprüfen Sie Protokolle regelmäßig auf Fehler und Warnungen
  • Behalten Sie "Information" als Standard-Protokollierungsstufe
  • Verwenden Sie "Debug" nur zur Fehlersuche (erzeugt viele Einträge) und stellen Sie danach zurück – mit "Debug" sind die Obergrenzen schnell erreicht und ältere Einträge gehen verloren
  • Archivieren Sie Protokolldateien, die Sie länger als 14 Tage aufbewahren möchten, rechtzeitig an einen anderen Ort

SMTP-Debug-Modus

Der SMTP-Debug-Modus ermöglicht eine detaillierte Diagnose des E-Mail-Versands. Bei Aktivierung werden alle ausgehenden E-Mails mit erweiterten Informationen protokolliert und optional als EML-Dateien gespeichert.

Funktionsumfang:

  • Detaillierte Protokollierung aller E-Mail-Details (Absender, Empfänger, Betreff, SMTP-Konto-Informationen)
  • Optionales Speichern jeder ausgehenden E-Mail als .eml-Datei zur Analyse
  • Bestätigungsprotokollierung nach erfolgreichem Versand

Konfigurationsparameter:

Parameter Typ Standard Beschreibung
Enabled bool false Aktiviert/Deaktiviert den SMTP-Debug-Modus
SaveEmlToDirectory string "" Verzeichnispfad zum Speichern von EML-Dateien. Leer = kein Speichern

Konfiguration in appsettings.json (Windows-Dienst):

"SmtpDebug": {
  "Enabled": true,
  "SaveEmlToDirectory": "C:\\Temp\\MailDebug"
}

Konfiguration als Umgebungsvariablen (Portainer Stack / Docker):

environment:
  # SMTP-Debug-Modus aktivieren
  - SmtpDebug__Enabled=true
  # Optional: EML-Dateien im Container speichern
  - SmtpDebug__SaveEmlToDirectory=/app/debug-mails

Wenn EML-Dateien im Container gespeichert werden sollen, muss ein Volume gemappt werden, damit die Dateien auch nach einem Container-Neustart verfügbar bleiben:

services:
  mesoworkerservice:
    environment:
      - SmtpDebug__Enabled=true
      - SmtpDebug__SaveEmlToDirectory=/app/debug-mails
    volumes:
      - type: bind
        source: //server/share/debug-mails  # Pfad auf dem Host
        target: /app/debug-mails

Protokollausgabe bei aktiviertem Debug-Modus:

Die Protokolleinträge werden mit dem Prefix [SMTP-DEBUG] auf der Stufe Warning geschrieben und enthalten:

  • SMTP-Konto-Details (EmailFrom, Host, Port, SSL/TLS-Einstellungen)
  • Absender- und Empfänger-Adressen (To, CC, BCC)
  • Betreff der E-Mail
  • Anzahl der Empfänger pro Typ
  • Pfad der gespeicherten EML-Datei (wenn SaveEmlToDirectory konfiguriert)

Beispiel einer Protokollausgabe:

[SMTP-DEBUG] === Mail wird gesendet ===
  SMTP-Account: [email protected], Host=smtp.firma.de, Port=587, SSL=False, StartTLS=True
  From:    [email protected]
  To:      [email protected]
  CC:      (keine)
  BCC:     [email protected]
  Subject: Bestellbestätigung REF-2024-001
  BCC-Count: 1 | To-Count: 1 | CC-Count: 0
[SMTP-DEBUG] EML gespeichert: /app/debug-mails/debug_20260217_143022_a1b2c3d4.eml
[SMTP-DEBUG] Mail erfolgreich gesendet via [email protected]: Subject="Bestellbestätigung REF-2024-001"

Wichtige Hinweise:

  • Der Debug-Modus sollte nur temporär zur Fehlerdiagnose aktiviert werden
  • Die Protokollierung erfolgt auf Stufe Warning, um auch bei Standard-Protokollierungsstufe sichtbar zu sein
  • Bei aktiviertem SaveEmlToDirectory werden alle ausgehenden E-Mails als Dateien gespeichert — achten Sie auf den Speicherplatz
  • EML-Dateien können mit jedem E-Mail-Client (z.B. Outlook, Thunderbird) geöffnet und analysiert werden
  • Im Container-Betrieb ohne Volume-Mapping gehen gespeicherte EML-Dateien bei Container-Neustart verloren

Wartungsaufgaben

Regelmäßige Aufgaben:

  1. Mail-Journal prüfen (täglich)

    • Überprüfen Sie fehlgeschlagene E-Mails
    • Analysieren Sie Trends bei Fehlern
  2. Stammdaten pflegen (wöchentlich)

    • Aktualisieren Sie E-Mail-Adressen von Kunden
    • Überprüfen Sie Ansprechpartner-Daten
  3. SMTP-Konten überwachen (wöchentlich)

    • Testen Sie SMTP-Verbindungen
    • Überprüfen Sie OAuth-Token (M365)
  4. Protokolldateien prüfen (wöchentlich)

    • Suchen Sie nach wiederkehrenden Fehlern
    • Überprüfen Sie Performance-Warnungen
  5. Service-Status überwachen (täglich)

    • Health-Check-Endpoint aufrufen: http://server:5000/health
    • Windows-Dienst-Status prüfen
  6. Updates einspielen (nach Bedarf)

    • Neue Container-Images deployen
    • Windows-Dienst aktualisieren
    • Konfigurationsänderungen testen

Troubleshooting:

Problem: E-Mails werden nicht versendet

  • Überprüfen Sie Mail-Journal auf Fehler
  • Prüfen Sie SMTP-Konto-Einstellungen
  • Testen Sie SMTP-Server-Erreichbarkeit
  • Überprüfen Sie Workflow-Filter-Einstellungen

Problem: Keine Empfänger gefunden

  • Überprüfen Sie Kundenstamm-Daten (E-Mail-Adressen)
  • Prüfen Sie Empfängerregeln in Mail-Einstellungen
  • Überprüfen Sie Ansprechpartner-Zuweisungen

Problem: Service startet nicht

  • Überprüfen Sie Lizenz-Einstellungen
  • Prüfen Sie Datenbankverbindungen
  • Kontrollieren Sie Protokolldateien

Mehrere Instanzen

Der WorkerService darf mehrfach gegen dieselbe Datenbank laufen. Eine Anwendungssperre in der Datenbank stellt sicher, dass jeder Job je Fälligkeit nur auf einer Instanz läuft; die übrigen Instanzen überspringen den Lauf und protokollieren das mit dem Wortlaut <Job> laeuft bereits auf einer anderen Instanz — Lauf uebersprungen. Wer sich fragt, warum ein Job auf einer Instanz „nichts tut", sucht zuerst nach dieser Meldung.

Was die Sperre leistet: Keine doppelten Mails, keine doppelten Buchungsstapel, keine doppelten Berichtsdateien. Fällt eine Instanz aus, übernimmt die andere beim nächsten Turnus.

Was sie nicht leistet: Ein übersprungener Lauf wird nicht nachgeholt. Nach einem harten Absturz kann die Sperre bis zu etwa einer Minute stehen bleiben, bis SQL Server die abgebrochene Verbindung bemerkt — der nächste Turnus holt das auf.

Lange Läufe: Die Sperre hängt an einer Datenbankverbindung, die für die Dauer des Laufs offen bleibt und dabei ungenutzt ist. Reißt diese Verbindung ab — durch ein Leerlauf-Zeitlimit einer Firewall, ein NAT-Gerät oder ein SQL-Server-Failover —, gibt SQL Server die Sperre frei, während der Job weiterläuft. Eine zweite Instanz könnte denselben Job dann parallel starten. Das System bemerkt das nicht und protokolliert es nicht. Für die üblichen Läufe im Sekundenbereich ist das ohne Bedeutung; relevant wird es bei Berichts- oder Banking-Läufen, die viele Minuten dauern. Wer solche Läufe im Mehrinstanzbetrieb fährt, sollte das Leerlauf-Zeitlimit auf dem Weg zur Datenbank prüfen.

Ausnahme — Sofort-Anstoss per HTTP: Die Zusage "keine doppelten Mails, keine doppelten Buchungsstapel" gilt nur für zeitgesteuerte Läufe über Quartz. Der manuelle Sofort-Anstoss POST /banking/trigger (ebenso /banking/rematch) läuft an Quartz vorbei — er führt seine Arbeit per Task.Run in einem eigenen Scope aus, ohne den VetoJobExecution-Haken der Laufsperre zu durchlaufen. Wird dieser Endpoint auf mehreren Instanzen gleichzeitig aufgerufen, sind doppelte Buchungsstapel weiterhin möglich.

Docker Compose: Die mitgelieferte docker-compose.portainer.yml ist trotz der Sperre auf Einzelbetrieb zugeschnitten — sie bindet einen festen Host-Port (${SERVICE_PORT:-5000}:5000) und ein gemeinsames Log-Volume. Die Sperre selbst erlaubt Mehrinstanzbetrieb; ein zweiter Container braucht dafür aber eine eigene Portbindung und ein eigenes Log-Volume (eigene Compose-Datei oder zweiter Dienst) — deploy.replicas: 2 allein reicht nicht.

Wenn die Sperre nicht auswertbar ist: Ist die Datenbank nicht erreichbar oder schlägt die Sperranfrage fehl, lässt das System den Job-Lauf zu, anstatt ihn zu blockieren. Der Grund: In der weit überwiegenden Zahl der Installationen läuft ohnehin nur eine einzige Instanz — dort wäre ein Blockieren bei nicht auswertbarer Sperre ein Ausfall des Jobs, ein Durchlassen bleibt dagegen folgenlos. Nur im Mehrinstanzbetrieb bedeutet dieser Zustand, dass für diesen Lauf wieder mehrere Instanzen parallel arbeiten können. Erkennbar ist er an einer Warnung im Log mit dem Wortlaut Laufsperre fuer {Job} nicht auswertbar — Lauf wird zugelassen..

Konfiguration: Abschalten mit "JobRunLock": { "Enabled": false }. Ohne konfigurierten ConnectionStrings:ConnectionString ist die Sperre wirkungslos und meldet das beim Start.

Den aktuellen Zustand zeigt der Health-Check-Endpoint GET /health/detailed im Abschnitt JobRunLocks.

HTTP-Schnittstelle und API-Schlüssel

Der Worker-Dienst bietet auf seinem Port (Standard 5000) einige HTTP-Endpunkte für Überwachung und Automatisierung. Alle Funktionen stehen auch in der Web-UI zur Verfügung; die Endpunkte sind ein Zusatz für Monitoring-Systeme und Skripte.

API-Schlüssel (ApiAuth:Key): Geschützte Endpunkte erwarten den Schlüssel im HTTP-Header X-Api-Key. Fehlt der Header oder stimmt der Wert nicht, antwortet der Dienst mit 401 Unauthorized.

Achtung – ohne Schlüssel sind die Endpunkte offen. Ist ApiAuth:Key nicht konfiguriert, lässt der Dienst aus Gründen der Abwärtskompatibilität jede Anfrage durch. Damit kann jeder, der den Port erreicht, Banking-Läufe anstoßen, Mails aus CRM-Fällen versenden und Protokollzeilen abrufen. Setzen Sie den Schlüssel deshalb bei jeder Installation, deren Port über den lokalen Rechner hinaus erreichbar ist, und geben Sie den Port in der Firewall nur für die Systeme frei, die ihn benötigen.

Konfiguration in der appsettings.json bzw. als Umgebungsvariable ApiAuth__Key:

"ApiAuth": {
  "Key": "langer-zufaelliger-wert"
}

Aufruf mit Schlüssel:

curl -H "X-Api-Key: langer-zufaelliger-wert" http://IHR-SERVER:5000/health/detailed

Endpunkte:

Endpunkt Schlüssel nötig Zweck
GET /health nein Basis-Zustand für Container-Healthchecks und Monitoring. Antwort Healthy, Degraded (Lizenz fehlt) oder Unhealthy (HTTP 503 bzw. 500)
GET /health/detailed ja Erweiterter Zustand: Lizenz, vorhandene Verbindungszeichenfolgen, Scheduler-Zustand mit allen Jobs und deren letzter und nächster Ausführung, Laufsperren (JobRunLocks), Laufzeitumgebung
GET /health/logs ja Die letzten 100 Zeilen der aktuellsten Protokolldatei aus /app/logs (nur Container-Betrieb)
POST /banking/trigger ja Stößt den Banking-Lauf sofort an (Kontoabruf, Zuordnung, Buchung). Läuft an der Laufsperre vorbei, siehe Mehrere Instanzen
POST /banking/rematch ja Wiederholt die Zuordnung noch nicht zugeordneter Transaktionen. Body optional: JournalIds (Liste von Transaktions-IDs, leer = alle offenen) und IncludeLlm (true oder leer = vollständige Zuordnung inkl. OP-Suche, Buchungsregeln und KI, false = nur Buchungsregeln)
POST /banking/lernmodus ja Startet die Lernmodus-Analyse für ein Bankkonto, siehe Lernmodus
GET /api/Mail/incidence/{Mandant}/{Fall-ID} ja Versendet die für einen einzelnen CRM-Fall konfigurierten E-Mails sofort, ohne auf den nächsten Turnus des Mail-Dienstes zu warten. Mandant ist die vierstellige Mandantennummer

Die Web-UI (Port 8012 in der Stack-Vorlage) hat keine dieser Endpunkte; ihr Zugriff ist über die Benutzeranmeldung geschützt.