trading-system-docs/notes/trading/system-docs/modul-15-monitoring-control.md

9.3 KiB
Raw Permalink Blame History

type _organized
Trading-Modul-System true

Modul-15: Monitoring-Control

Status: FREIGEGEBEN (20.08.2026) · Container Modul-15-Monitoring-Control · Image monitoring-control:0.1.0

Zweck

Zentrale technische Überwachung und Sicherheits-/Kontrollebene des Modul-Trading-Systems. Überwacht die Dienste M03M14 (Health/Readiness/Erreichbarkeit) plus RabbitMQ-Queues/Consumer und PostgreSQL und leitet daraus deterministisch einen globalen Trading-Status (ENABLED / PAUSED / HALTED / UNKNOWN) ab.

Restriktionen (Nutzer-Vorgabe):

  • Keine KI/ML, keine Trading-Entscheidungen, keine Brokerorders, keine Shell-/Docker-Control-Rechte.
  • FAIL-CLOSED: Bei unklarem/kritischem Zustand wird Trading sicher blockiert (HALTED).
  • M15 unerreichbar → M09 behandelt den Zustand als HALTED (FAIL-CLOSED, siehe M15→M09-Anbindung, FREIGEGEBEN).
  • Keine Event-Schleifen: Events nur bei Status-Änderung, dedupliziert.
  • Container wird nicht automatisch neu gestartet/gekillt — M15 beobachtet und entscheidet Status.
  • Port 55015 nur Docker-intern (expose, kein Host-Port).

Architektur / Datenfluss

M03M14 (health/ready)  RabbitMQ (Queues)  PostgreSQL
        │                       │              │
        └──────────┬────────────┴──────────────┘
                   ▼
        Modul-15-Monitoring-Control
        ├── probe/     MonitoringProbe (HTTP-health + RMQ passive declare + PG)
        ├── rules/     MonitoringRules (deterministisch, FAIL-CLOSED, versioniert)
        ├── core/      MonitorService (Status-Engine, Single Source of Truth)
        ├── storage/   Persistenz (PostgreSQL: system_health/service_health/control_event)
        ├── publisher/ ControlPublisher (market.control, nur bei Status-Änderung)
        └── api/main.py REST-API (intern, Port 55015)

Status → system_health (append), Services → service_health (upsert), Änderungen → control_event (append-only Audit).

API (Docker-intern, Port 55015, kein öffentliches Port-Mapping)

GET /health                 liveness
GET /health/ready           readiness (postgresql)
GET /monitoring/status      aktueller System-Status + Trading-Status (internes State-Modell)
GET /monitoring/services    aktueller Zustand aller überwachten Services/Queues
GET /control/status         Control-Status (manual_override, control_api_enabled)
GET /control/trading-state  autoritativer Trading-Status für M09
POST /control               manuelle Control PAUSE/HALT/RESUME (nur wenn CONTROL_API_ENABLED=true)

Deterministische Regeln (Rules-Engine, Version 0.1.0)

Präzedenz strikt von oben nach unten (FAIL-CLOSED):

  1. UNKNOWN — PostgreSQL nicht erreichbar → nicht verlässlich → HALTED.
  2. UNHEALTHY/HALTED — kritische Infrastruktur (PG/RabbitMQ) oder Execution-Pfad down.
  3. DEGRADED/PAUSED — nicht-kritische Dienste down / stale.
  4. HEALTHY/ENABLED — alles gut.
Bedingung System Trading Reason-Code
PostgreSQL nicht erreichbar UNHEALTHY HALTED POSTGRESQL_UNREACHABLE (+ PERSISTENCE_FAILURE)
RabbitMQ nicht erreichbar UNHEALTHY HALTED RABBITMQ_UNREACHABLE
Kritischer Service down (M03M09) UNHEALTHY HALTED CRITICAL_SERVICE_DOWN:<id>
Market Data stale (> max_age) UNHEALTHY HALTED MARKET_DATA_STALE
Kritische Queue Consumer fehlt HALTED NO_CONSUMER_<queue>
Kritischer Queue-Backlog ≥1000 HALTED QUEUE_BACKLOG_CRIT:<queue>:<n>
Nicht-kritische Unhealthy (Analytics/Notification) DEGRADED PAUSED CRITICAL_SERVICE_DOWN/NO_CONSUMER_…
Queue-Backlog ≥100 / Warning DEGRADED PAUSED QUEUE_BACKLOG:<queue>:<n>
Alles healthy HEALTHY ENABLED

FAIL-CLOSED-Hinweis: UNKNOWN Trading-Status wird in der API auf HALTED gemappt (nie ENABLED aus unklarem Zustand).

Events (market.control Exchange, keine Event-Schleife)

Events werden nur bei Status-Änderung publiziert (Idempotenz) — nie bei jedem Poll:

Event-Typ Routing-Key Anlass
system.degraded system.degraded System → DEGRADED
system.halted system.halted System → UNHEALTHY (HALT)
system.recovered system.recovered System → HEALTHY
trading.state trading.state Trading-Status-Änderung
service.unhealthy service.unhealthy Einzelner Service UNHEALTHY

Persistenz / Audit (PostgreSQL Modul-01)

  • system_health — append-only Zeile pro Beobachtung (aktueller Status + reason_codes).
  • service_health — Upsert pro service_id (aktueller Zustand jedes Services/Queue).
  • control_eventappend-only Audit-Trail jeder Status-/Trading-Änderung (STATE_CHANGE) und manuellen Control-Aktion (MANUAL_*). Idempotent — eine Änderung wird genau einmal auditiert.

Manuelle Control (PAUSE/HALT/RESUME)

  • Nur wenn CONTROL_API_ENABLED=true (Default false → manuelle Control über API deaktiviert, nur Regel-getrieben).
  • RESUME wird verweigert (RESUME_BLOCKED_CRITICAL_CAUSE), solange eine kritische Ursache besteht.
  • Jede manuelle Aktion wird append-only in control_event auditiert.

Sicherheit

  • Keine Secrets in DB/Logs/Doku/Commits — Zugangsdaten ausschließlich via Environment (Compose).
  • Kein Docker-Socket, keine Shell-/Docker-Control-Rechte (CMD=python main.py).
  • Port 55015 nur intern (expose), restart: unless-stopped, non-root (uid 1001).
  • Env: POSTGRES_*, RABBITMQ_*, CONTROL_API_ENABLED.

Compose / Betrieb

  • Netzwerk trading-modules, DB-Host Modul-01-PostgreSQL, RabbitMQ Modul-02-RabbitMQ.
  • Env per Compose, Zugangsdaten nur via ENV (POSTGRES_*, RABBITMQ_*), nie hart kodiert.

Unit-Tests

  • tests/test_monitoring.py: 19/19 grün — deterministische Rules, FAIL-CLOSED (PG/RabbitMQ/Critical), stale, Queue-Consumer, Idempotenz, Audit genau einmal, Recovery, Reconnect, keine Secrets, state_version-Inkrementierung.

E2E-Verifikation (VPS, 20.08.2026) — 17 Szenarien

Alle 17 verifiziert (System-/Trading-Status via Loop, API /control/trading-state + /monitoring/status konsistent):

  1. Normalzustand: HEALTHY/ENABLED — API, State-Modell, Loop identisch.
  2. PG-Ausfall: HALTED, POSTGRESQL_UNREACHABLE+PERSISTENCE_FAILURE, Audit genau einmal.
  3. RabbitMQ-Ausfall: HALTED, RABBITMQ_UNREACHABLE.
  4. Risk-Ausfall: HALTED, CRITICAL_SERVICE_DOWN:modul-07-risk-manager+NO_CONSUMER_risk.input.
  5. Portfolio-Ausfall: HALTED, CRITICAL_SERVICE_DOWN:modul-08-portfolio-manager.
  6. Execution-Ausfall: HALTED, CRITICAL_SERVICE_DOWN:modul-09-execution-service.
  7. Analytics-Ausfall: DEGRADED + PAUSED (Trading nicht vollständig kill).
  8. Notification-Ausfall: DEGRADED + PAUSED.
  9. Market Data stale: HALTED, MARKET_DATA_STALE; Recovery nach frischen Daten.
  10. Kritischer Consumer fehlt: HALT-Severity korrekt (NO_CONSUMER auf kritischer Queue).
  11. Queue-Backlog: Warning/HALT gemäß Schwelle (100/1000, Unit-getestet).
  12. Recovery: Ursache erneut geprüft, kein Auto-RESUME solange Ursache, Status konsistent, kein Event-Spam.
  13. Manuelle Controls: mit CONTROL_API_ENABLED=false sauber abgelehnt (control_api_disabled); Trading unangetastet.
  14. Idempotenz/Event-Flut: stabiler Zustand → keine wiederholten SYSTEM_HALTED/SERVICE_UNHEALTHY (nur 1 Audit je Änderung).
  15. RabbitMQ-Reconnect: automatisch (alle Recovery-Zyklen), keine Zombies, keine Eventverluste.
  16. Audit: control_event/system_health/service_health vollständig + zeitlich nachvollziehbar.
  17. Security: kein öffentlicher Port (PortBindings {}), kein Docker-Socket, keine Secrets im Compose/Logs.

Bekannte Design-Hinweise (für separaten M15→M09-Vorschlag)

  • M03M06 (Market-Data-Pipeline) sind in CRITICAL_SERVICES klassifiziert. Ausfall eines einzelnen Daten-Moduls führt so zu HALTED (über CRITICAL_SERVICE_DOWN), nicht ausschließlich über MARKET_DATA_STALE. Das ist fachlich konservativ aber zu klären (nur Data-Pipeline vs. Execution-Pfad).
  • DEGRADED → PAUSED (nicht ENABLED): bei Analytics/Notification-Ausfall wird Trading vorsichtig gestoppt, nicht vollständig killed. Design-Entscheidung, im Vorschlag benannt.
  • PG-Ausfall ⇒ PERSISTENCE_FAILURE: ohne PG kann control_event-Audit nicht geschrieben werden (fachlich korrekt FAIL-CLOSED), aber Audit-Lücke im Fehlerfenster.

Freigabe

  • FREIGEGEBEN (20.08.2026, Nutzer-Bestätigung). Implementierung + E2E (17 Szenarien) grün.
  • M09-Anbindung umgesetzt (Variante C, Event-Cache + HTTP-Final-Check) — siehe modul-15-m09-anbindung-implementierung.md, FREIGEGEBEN.

Nächste Module

  • Modul-16 ff. — noch Platzhalter (alpine), NICHT gestartet.

Geändert

Geändert von: Rain Ocampo
Datum: 20.08.2026
Grund: Modul-15-Monitoring-Control dokumentiert — implementiert + E2E-verifiziert (17 Szenarien grün),
       Rules/API/Events/Audit/Security dokumentiert, NICHT FREIGEGEBEN.
Geändert von: Rain Ocampo
Datum: 20.08.2026
Grund: Modul-15-Monitoring-Control auf FREIGEGEBEN gesetzt (Nutzer-Bestätigung 20.08.2026).
       M15→M09-Anbindung (Variante C) als umgesetzt/FREIGEGEBEN vermerkt; Unit-Tests 19/19.