Erweiterungen

This commit is contained in:
2025-10-23 12:18:42 +02:00
parent 98974dcc2a
commit e7d18533b5
37 changed files with 5028 additions and 490 deletions

318
MESSAGING_LAYER.md Normal file
View File

@@ -0,0 +1,318 @@
# Message Delivery Layer - Implementierungsdokumentation
## Übersicht
Der **Message Delivery Layer** ist eine neue Abstraktionsschicht zwischen der Anwendungslogik und dem MQTT-Transport. Er bietet:
-**Zuverlässige Nachrichtenzustellung** mit Bestätigungsmechanismus
-**Automatische Wiederholungsversuche** bei fehlgeschlagenen Zustellungen
-**Protokoll-Abstraktion** für einfachen Austausch von MQTT gegen andere Transporte
-**Vollständiges Audit-Log** aller Nachrichten
-**Queue-basiertes Design** für Skalierbarkeit
## Architektur
```
Application Layer (MessageController, Services)
MessageDeliveryService (Envelope-Wrapping, Queue-Management)
MessagingTransport Interface (Protokoll-Abstraktion)
MqttTransportAdapter (MQTT-spezifische Implementierung)
MqttV5ClientManager (HiveMQ Client)
```
## Komponenten
### 1. Datenmodelle (`messaging/model/`)
#### MessageEnvelope
Wrapper für alle Nachrichten mit Metadaten:
- `messageId`: Eindeutige UUID
- `timestamp`: Erstellungszeitpunkt
- `topic`: Ziel-Topic
- `payload`: Ursprüngliche Nachricht
- `requiresAck`: Bestätigung erforderlich?
- `retryCount`: Anzahl Wiederholungsversuche
- `expiresAt`: Ablaufzeitpunkt
#### PendingDelivery
Tracking-Objekt für ausstehende Zustellungen:
- `messageId`: Referenz zur Envelope
- `status`: PENDING, SENT, ACKNOWLEDGED, FAILED, EXPIRED
- `retryCount`: Aktuelle Wiederholungsversuche
- `nextRetryAt`: Zeitpunkt des nächsten Versuchs
- `envelopeData`: Serialisierte Envelope-Daten
#### AcknowledgmentMessage
Bestätigungsnachricht vom Client:
- `messageId`: ID der bestätigten Nachricht
- `status`: RECEIVED, PROCESSED, FAILED
- `clientId`: Absender der Bestätigung
- `errorMessage`: Optional bei Fehler
### 2. Transport Layer (`messaging/transport/`)
#### MessagingTransport Interface
Protokoll-agnostische Schnittstelle:
```java
CompletableFuture<Void> send(String topic, byte[] payload, TransportOptions options);
void subscribe(String topicPattern, MessageHandler handler);
boolean isConnected();
String getTransportType();
```
#### MqttTransportAdapter
MQTT-Implementierung des Transport-Interfaces:
- Adaptiert HiveMQ MQTT Client
- Unterstützt MQTT-Wildcards (+ und #)
- QoS-Mapping (0, 1, 2)
### 3. Delivery Service (`messaging/delivery/`)
#### MessageDeliveryService
Zentrale Orchestrierung:
- `sendMessage()`: Nachricht mit Tracking senden
- `handleIncomingMessage()`: Eingehende Envelope verarbeiten
- `handleAcknowledgment()`: Bestätigung verarbeiten
- `retryPendingDeliveries()`: Wiederholungsversuche durchführen
- `cleanupOldDeliveries()`: Alte Einträge aufräumen
#### AcknowledgmentHandler
Routing eingehender Nachrichten zur Anwendungslogik:
- Unwrapping der Envelope
- Routing basierend auf Topic-Pattern
- Delegation an MessageController
#### RetryScheduler
Geplante Tasks:
- Retry-Task: Alle 30 Sekunden (konfigurierbar)
- Cleanup-Task: Stündlich (konfigurierbar)
### 4. Repositories
#### MessageEnvelopeRepository
Speicherung aller Envelope-Objekte in MongoDB Collection `message_envelopes`
#### PendingDeliveryRepository
Tracking ausstehender Zustellungen in MongoDB Collection `pending_deliveries`
## Nachrichtenfluss
### Outbound (Server → Client)
1. **Anwendung** ruft `MessageDeliveryService.sendMessage()` auf
2. **MessageEnvelope** wird erstellt mit eindeutiger `messageId`
3. **PendingDelivery** wird in Datenbank gespeichert (Status: PENDING)
4. **Envelope** wird als JSON serialisiert
5. **Transport** sendet Nachricht via MQTT
6. **Status** wird auf SENT aktualisiert, `nextRetryAt` gesetzt
7. **Client** empfängt Nachricht und sendet ACK
8. **AcknowledgmentHandler** verarbeitet ACK
9. **PendingDelivery** wird auf ACKNOWLEDGED gesetzt
### Inbound (Client → Server)
1. **MQTT** empfängt Nachricht auf Topic
2. **MqttTransportAdapter** leitet an MessageDeliveryService weiter
3. **MessageEnvelope** wird aus JSON deserialisiert
4. **ACK** wird automatisch an Client gesendet (falls `requiresAck=true`)
5. **AcknowledgmentHandler** routet Payload zur Anwendung
6. **MessageController** verarbeitet Business-Logik
## Retry-Mechanismus
### Exponential Backoff
```
Versuch 1: 5 Sekunden
Versuch 2: 10 Sekunden (5s × 2.0)
Versuch 3: 20 Sekunden (10s × 2.0)
Versuch 4: 40 Sekunden (20s × 2.0)
Maximum: 5 Minuten
```
### Ablauf
1. **RetryScheduler** läuft alle 30 Sekunden
2. Findet alle `PendingDelivery` mit Status SENT und `nextRetryAt` in Vergangenheit
3. Prüft auf Ablauf (`expiresAt`) und Max-Retries
4. Sendet Nachricht erneut via Transport
5. Aktualisiert `retryCount` und `nextRetryAt`
## Konfiguration
### application.properties
```properties
# Message Delivery Layer Configuration
app.messaging.delivery.max-retries=3
app.messaging.delivery.retry-initial-delay=5s
app.messaging.delivery.retry-max-delay=5m
app.messaging.delivery.retry-backoff-multiplier=2.0
app.messaging.delivery.ack-timeout=30s
app.messaging.delivery.message-expiry=24h
app.messaging.delivery.cleanup-interval-minutes=60
app.messaging.delivery.retry-interval-seconds=30
app.messaging.delivery.acknowledged-retention-days=7
```
## MQTT Topics
### Outbound (Server → Client)
```
/client/{clientId}/message # Chat-Nachrichten (wrapped)
/client/{clientId}/jobs # Job-Zuweisungen (wrapped)
/client/{clientId}/auth # Login-Antworten (wrapped)
```
### Inbound (Client → Server)
```
/server/{clientId}/task_completed # Task-Abschlüsse (wrapped)
/server/{clientId}/message # Chat-Nachrichten (wrapped)
/server/{clientId}/jobs/assigned # Job-Anfragen (wrapped)
/server/login # Login-Anfragen (wrapped)
```
### Acknowledgments
```
/ack/server/{messageId} # Client → Server ACK
/ack/client/{clientId}/{messageId} # Server → Client ACK
```
## Migration bestehender Clients
### Phase 1: Server-seitig (✅ Abgeschlossen)
- Message Delivery Layer implementiert
- MqttPublisher nutzt jetzt MessageDeliveryService
- Backward-kompatibel: Legacy-Nachrichten werden weiterhin verarbeitet
### Phase 2: Client-seitig (TODO)
Flutter-App muss angepasst werden:
1. **Envelope-Handling**
```dart
class MessageEnvelope {
String messageId;
DateTime timestamp;
String topic;
Map<String, dynamic> payload;
bool requiresAck;
}
```
2. **Empfang**
```dart
void handleIncomingMessage(String topic, String json) {
final envelope = MessageEnvelope.fromJson(json);
// ACK senden
if (envelope.requiresAck) {
sendAcknowledgment(envelope.messageId);
}
// Payload verarbeiten
processPayload(envelope.payload);
}
```
3. **ACK senden**
```dart
void sendAcknowledgment(String messageId) {
final ack = {
'messageId': messageId,
'status': 'RECEIVED',
'timestamp': DateTime.now().toIso8601String(),
'clientId': myClientId
};
mqtt.publish('/ack/server/$messageId', jsonEncode(ack));
}
```
4. **Senden**
```dart
void sendMessage(String topic, Map<String, dynamic> payload) {
final envelope = MessageEnvelope(
messageId: Uuid().v4(),
timestamp: DateTime.now(),
topic: topic,
payload: payload,
requiresAck: true
);
mqtt.publish(topic, jsonEncode(envelope.toJson()));
}
```
## Monitoring & Debugging
### Logging
Alle Komponenten loggen mit Präfix:
- `[MessageDelivery]`: MessageDeliveryService
- `[MqttTransport]`: MqttTransportAdapter
- `[AckHandler]`: AcknowledgmentHandler
- `[RetryScheduler]`: RetryScheduler
- `[MessagingConfig]`: MessagingConfig
### Datenbank-Queries
**Ausstehende Zustellungen:**
```javascript
db.pending_deliveries.find({ status: "SENT" })
```
**Fehlgeschlagene Zustellungen:**
```javascript
db.pending_deliveries.find({ status: "FAILED" })
```
**Retry-Statistiken:**
```javascript
db.pending_deliveries.aggregate([
{ $group: { _id: "$status", count: { $sum: 1 } } }
])
```
**Nachrichten eines Clients:**
```javascript
db.pending_deliveries.find({ client_id: "client123" })
```
## Vorteile
### Zuverlässigkeit
- Garantierte Zustellung durch Retry-Mechanismus
- Persistierung in MongoDB verhindert Datenverlust
- Acknowledgment-Tracking für Nachvollziehbarkeit
### Skalierbarkeit
- Queue-basiertes Design
- Asynchrone Verarbeitung mit CompletableFuture
- Scheduled Tasks für Hintergrundverarbeitung
### Wartbarkeit
- Klare Trennung der Verantwortlichkeiten
- Protokoll-Abstraktion ermöglicht einfachen Austausch
- Umfangreiches Logging für Debugging
### Flexibilität
- Konfigurierbare Retry-Parameter
- Verschiedene DeliveryOptions (standard, fireAndForget, critical)
- Erweiterbar für andere Transporte (WebSocket, gRPC, etc.)
## Nächste Schritte
1. ✅ Server-seitige Implementierung abgeschlossen
2. ⏳ Flutter-App anpassen (Envelope-Handling)
3. ⏳ Integration-Tests schreiben
4. ⏳ Monitoring-Dashboard erstellen
5. ⏳ Performance-Optimierung
6. ⏳ Dokumentation für Client-Entwickler
## Support
Bei Fragen oder Problemen:
- Logs prüfen: `logs/votianlt.log`
- MongoDB Collections: `message_envelopes`, `pending_deliveries`
- Konfiguration: `application.properties`