9.2 KiB
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 Trading-Systems.
Überwacht die Dienste M03–M14 (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
M03–M14 (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):
- UNKNOWN — PostgreSQL nicht erreichbar → nicht verlässlich →
HALTED. - UNHEALTHY/HALTED — kritische Infrastruktur (PG/RabbitMQ) oder Execution-Pfad down.
- DEGRADED/PAUSED — nicht-kritische Dienste down / stale.
- 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 (M03–M09) | 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 proservice_id(aktueller Zustand jedes Services/Queue).control_event— append-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(Defaultfalse→ 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_eventauditiert.
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-HostModul-01-PostgreSQL, RabbitMQModul-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):
- Normalzustand:
HEALTHY/ENABLED— API, State-Modell, Loop identisch. - PG-Ausfall:
HALTED,POSTGRESQL_UNREACHABLE+PERSISTENCE_FAILURE, Audit genau einmal. - RabbitMQ-Ausfall:
HALTED,RABBITMQ_UNREACHABLE. - Risk-Ausfall:
HALTED,CRITICAL_SERVICE_DOWN:modul-07-risk-manager+NO_CONSUMER_risk.input. - Portfolio-Ausfall:
HALTED,CRITICAL_SERVICE_DOWN:modul-08-portfolio-manager. - Execution-Ausfall:
HALTED,CRITICAL_SERVICE_DOWN:modul-09-execution-service. - Analytics-Ausfall:
DEGRADED+PAUSED(Trading nicht vollständig kill). - Notification-Ausfall:
DEGRADED+PAUSED. - Market Data stale:
HALTED,MARKET_DATA_STALE; Recovery nach frischen Daten. - Kritischer Consumer fehlt: HALT-Severity korrekt (NO_CONSUMER auf kritischer Queue).
- Queue-Backlog: Warning/HALT gemäß Schwelle (100/1000, Unit-getestet).
- Recovery: Ursache erneut geprüft, kein Auto-RESUME solange Ursache, Status konsistent, kein Event-Spam.
- Manuelle Controls: mit
CONTROL_API_ENABLED=falsesauber abgelehnt (control_api_disabled); Trading unangetastet. - Idempotenz/Event-Flut: stabiler Zustand → keine wiederholten SYSTEM_HALTED/SERVICE_UNHEALTHY (nur 1 Audit je Änderung).
- RabbitMQ-Reconnect: automatisch (alle Recovery-Zyklen), keine Zombies, keine Eventverluste.
- Audit:
control_event/system_health/service_healthvollständig + zeitlich nachvollziehbar. - Security: kein öffentlicher Port (PortBindings
{}), kein Docker-Socket, keine Secrets im Compose/Logs.
Bekannte Design-Hinweise (für separaten M15→M09-Vorschlag)
- M03–M06 (Market-Data-Pipeline) sind in
CRITICAL_SERVICESklassifiziert. Ausfall eines einzelnen Daten-Moduls führt so zuHALTED(überCRITICAL_SERVICE_DOWN), nicht ausschließlich überMARKET_DATA_STALE. Das ist fachlich konservativ aber zu klären (nur Data-Pipeline vs. Execution-Pfad). - DEGRADED →
PAUSED(nichtENABLED): bei Analytics/Notification-Ausfall wird Trading vorsichtig gestoppt, nicht vollständig killed. Design-Entscheidung, im Vorschlag benannt. - PG-Ausfall ⇒
PERSISTENCE_FAILURE: ohne PG kanncontrol_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.