meldestelle/infrastructure/messaging/README-INFRA-MESSAGING.md
StefanMoCoAt d87a5a4a93 feat(infra-messaging): Implement fully reactive Kafka producer and consumer
This commit introduces a comprehensive refactoring of the messaging module to establish a fully reactive, non-blocking, and robust infrastructure for Kafka-based communication.

Features & Refinements
Reactive Publisher:

The KafkaEventPublisher has been refactored from a blocking implementation (KafkaTemplate) to a fully non-blocking, reactive one using Spring's ReactiveKafkaProducerTemplate.

The EventPublisher interface now returns reactive types (Mono, Flux) to reflect the asynchronous nature of the operations.

Reactive Consumer:

A new KafkaEventConsumer has been implemented, providing a standardized, reusable, and reactive way for services to consume events.

It encapsulates the complexity of reactor-kafka and exposes a simple receiveEvents<T>(topic) method that returns a Flux<T>.

Architectural Cleanup:

The Spring configuration has been split. The basic ProducerFactory and consumer properties reside in messaging-config, while the reactive-specific ReactiveKafkaProducerTemplate bean is now correctly located in messaging-client.

Testing
Added Kafka Integration Test: A new KafkaIntegrationTest has been created to ensure the reliability of the messaging infrastructure.

The test uses Testcontainers to spin up a real Apache Kafka broker for end-to-end validation.

Project Reactor's StepVerifier is used to test the reactive streams deterministically, avoiding flaky tests.

The test correctly manages the lifecycle of Kafka producers to ensure clean shutdown without hanging threads.

Bug Fixes
Resolved UninitializedPropertyAccessException in tests by making the KafkaConfig test-friendly.

Fixed IllegalStateException related to Testcontainers lifecycle by making the container a static resource.

Corrected compilation errors in tests related to resource cleanup by using the concrete DefaultKafkaProducerFactory type.
2025-08-10 00:02:59 +02:00

3.9 KiB

Infrastructure/Messaging Module

Überblick

Das Messaging-Modul stellt die Infrastruktur für die asynchrone, reaktive Kommunikation zwischen den Microservices bereit. Es nutzt Apache Kafka als hochperformanten, verteilten Message-Broker und ist entscheidend für die Entkopplung von Services und die Implementierung einer skalierbaren, ereignisgesteuerten Architektur.

Architektur

Das Modul ist in zwei spezialisierte Komponenten aufgeteilt, um Konfiguration von der Client-Logik zu trennen:

infrastructure/messaging/ ├── messaging-config/ # Stellt die zentrale Kafka-Konfiguration bereit └── messaging-client/ # Stellt wiederverwendbare, reaktive Clients bereit

messaging-config

Dieses Modul zentralisiert die grundlegende Kafka-Konfiguration für das gesamte Projekt.

  • Zweck: Definiert Spring-Beans für die ProducerFactory (Basis für Producer) und eine Map mit Standard-Konfigurationen für Consumer (z.B. bootstrap-servers, group-id, Serializer).
  • Vorteil: Stellt Konsistenz sicher und vereinfacht die Einrichtung neuer Producer oder Consumer in den Services.

messaging-client

Dieses Modul baut auf der Konfiguration auf und stellt wiederverwendbare High-Level-Komponenten für die Interaktion mit Kafka bereit.

  • Zweck:
    • KafkaEventPublisher: Ein reaktiver, nicht-blockierender Service zum Senden von Nachrichten. Er nutzt den ReactiveKafkaProducerTemplate von Spring.
    • KafkaEventConsumer: Ein reaktiver Service zum Empfangen von Nachrichten. Er kapselt die Komplexität von reactor-kafka und gibt einen kontinuierlichen Flux-Stream von Events zurück.
  • Vorteil: Kapselt die Komplexität der reaktiven Kafka-API. Ein Fach-Service muss nur noch reaktive Streams (Mono, Flux) handhaben, ohne sich um die Details der Kafka-Interaktion zu kümmern.

Verwendung

Ein Microservice, der Nachrichten senden oder empfangen möchte, deklariert eine Abhängigkeit zu :infrastructure:messaging:messaging-client und injiziert die entsprechenden Interfaces.

Beispiel für das Senden einer Nachricht (nicht-blockierend):

@Service
class EventNotificationService(
    private val eventPublisher: EventPublisher
) {
    fun notifyNewEvent(eventDetails: EventDetails) {
        val topic = "new-events-topic"
        eventPublisher.publishEvent(topic, eventDetails.id, eventDetails)
            .subscribe(
                null, // onComplete: Nichts zu tun
                { error -> logger.error("Failed to send message to topic '{}'", topic, error) }
            )
        // Die Methode kehrt sofort zurück, ohne auf die Bestätigung von Kafka zu warten.
    }
}

Beispiel für das Empfangen von Nachrichten (reaktiv):

@Component
class EventListener(
    private val eventConsumer: EventConsumer
) {
    @PostConstruct
    fun listenForEvents() {
        val topic = "new-events-topic"
        eventConsumer.receiveEvents<EventDetails>(topic)
            .subscribe { event ->
                logger.info("Received new event with ID: {}", event.id)
                // Geschäftslogik zur Verarbeitung des Events...
            }
    }
}

Testing-Strategie

Die Zuverlässigkeit des Moduls wird durch einen umfassenden Integrationstest sichergestellt, der auf dem "Goldstandard"-Prinzip beruht:

  • *Testcontainers: Der KafkaIntegrationTest startet einen echten Apachen Kafka Docker-Container, um die Funktionalität unter realen Bedingungen zu validieren.

  • *Reaktives Testen: Der Test nutzt Project Reactor's StepVerifier, um die reaktiven Streams (Mono, Flux) deterministisch und ohne unzuverlässige Thread.sleep-Aufrufe zu überprüfen.

  • *Lifecycle Management: Der Test-Lebenszyklus wird sauber über @BeforeEach und @AfterEach verwaltet, um sicherzustellen, dass alle Ressourcen (insbesondere Producer-Threads) nach jedem Test korrekt freigegeben werden.


Letzte Aktualisierung: 9. August 2025