Modul-15 Monitoring-Control dokumentiert (E2E 17 Szenarien gruen, noch nicht freigegeben, 20.08.2026)
This commit is contained in:
parent
4fc967835a
commit
4f97b97ed4
1 changed files with 140 additions and 0 deletions
140
modul-15-monitoring-control.md
Normal file
140
modul-15-monitoring-control.md
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
# Modul-15: Monitoring-Control
|
||||
|
||||
**Status: IMPLEMENTIERT & E2E-verifiziert (noch NICHT freigegeben)** · 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` (siehe Design-Vorschlag M15→M09, noch offen).
|
||||
- **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):
|
||||
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 (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 pro `service_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`** (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`: **18/18 grün** — deterministische Rules, FAIL-CLOSED (PG/RabbitMQ/Critical), stale, Queue-Consumer, Idempotenz, Audit genau einmal, Recovery, Reconnect, keine Secrets.
|
||||
|
||||
## 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)
|
||||
- **M03–M06 (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
|
||||
- **Noch NICHT freigegeben.** Implementierung + E2E (17 Szenarien) grün. Freigabe ausstehend.
|
||||
- M09-Anbindung **nicht** umgesetzt (Design-Vorschlag separat).
|
||||
|
||||
## 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.
|
||||
```
|
||||
Loading…
Reference in a new issue