Arbeiten mit Events

In modernen Systemen, die sich an Architektur-Best-Practices wie DDD (Domain-Driven Design) und Clean Architecture orientieren, sind Events grundlegende Mechanismen, um ZustandsĂ€nderungen zu modellieren und asynchrone Kommunikation zwischen Komponenten oder Systemen zu ermöglichen. Ein Event reprĂ€sentiert etwas, das bereits im AnwendungsdomĂ€nenbereich passiert ist und fĂŒr andere Teile des Systems oder externe Dienste von Interesse sein kann.

DomÀnenereignisse

DomĂ€nenereignisse stellen wichtige Fakten dar, die im Kontext der Anwendung aufgetreten sind. Sie werden intern im System erzeugt und konsumiert, wodurch ZustandsĂ€nderungen entkoppelt propagiert werden können, das heißt, die Objekte mĂŒssen sich nicht direkt kennen.

Wann sollte ein DomÀnenereignis verwendet werden?

  • Immer dann, wenn eine Operation eine signifikante Änderung im DomĂ€nenmodell erzeugt und es notwendig ist, andere Teile des Systems zu benachrichtigen oder auszulösen.
  • Um das DomĂ€nenmodell kohĂ€rent zu halten und es zu ermöglichen, dass verschiedene Prozesse ausgelöst werden, ohne direkte AbhĂ€ngigkeiten zwischen Modulen oder Services zu erzeugen.

In Lino ist das Erstellen eines neuen DomĂ€nenereignisses einfach. Sie können ausfĂŒhren:

lino event new

Der CLI-Assistent wird Folgendes abfragen:

  • Service – Der Service, in dem das Ereignis erstellt wird.
  • Modul – Das Modul, in dem das Ereignis erstellt wird (nur in modularen Services).
  • EntitĂ€t – Die EntitĂ€t, in der das Ereignis erstellt/assoziiert wird.
  • Ereignistyp – DomĂ€nenereignis oder Integrationsereignis.
  • Ereignisname – Im DomĂ€nenkontext verwendeter Name, der mit der EntitĂ€t verknĂŒpft wird.

Beispiel

Beim Erstellen des DomĂ€nenereignisses UserCreated, das mit der EntitĂ€t User verknĂŒpft ist, erstellt das System automatisch ein Ereignis mit dem Namen UserCreatedDomainEvent. Dieser Name macht fĂŒr jeden Teil des Systems, der das Ereignis konsumiert, deutlich, dass die Benutzererstellung bereits abgeschlossen ist.

Von Lino generierte Struktur:

MyApp/
└── src/
    └── Services/
        └── MyService/
            └── Domain/
                ├── MyApp.MyService.Domain.csproj
                └── Aggregates/
                    └── Users/
                        ├── User.cs
                        ├── Errors/
                        ├── Events/
                        │   └── UserCreatedDomainEvent.cs
                        ├── Repositories/
                        └── Resources/

DomÀnen-Ereignis-Handler

Ein Domain Event Handler ist eine Klasse, die dafĂŒr verantwortlich ist, auf ein DomĂ€nen-Ereignis zu reagieren und Aktionen im Zusammenhang mit dem internen Zustand der Anwendung auszufĂŒhren, immer innerhalb desselben Transaktionskontexts.

Der Hauptzweck dieser Handler besteht darin, das System kohĂ€rent und entkoppelt zu halten, sodass zusĂ€tzliche Regeln angewendet werden können, ohne die zentrale Logik der EntitĂ€t oder des Aggregats zu ĂŒberlasten.

Zum Beispiel kann es nach der Erstellung eines User erforderlich sein, Statistiken zu aktualisieren, ein internes Protokoll zu erstellen oder ein anderes Aggregat zu benachrichtigen. Diese Aktionen machen im Kontext der DomÀne Sinn und können synchron erfolgen, wodurch sofortige Konsistenz gewÀhrleistet wird.

Operationen, die jedoch von externen Ressourcen abhĂ€ngen – wie das Versenden von E-Mails oder das Aufrufen von Drittanbieter-APIs – sollten nicht direkt aus DomĂ€nenereignissen ausgefĂŒhrt werden, da dies die Transaktion an langsame oder instabile Aufgaben binden wĂŒrde. In solchen FĂ€llen kann die DomĂ€ne ein Integrationsereignis erzeugen (im Outbox-Mechanismus protokolliert), das spĂ€ter asynchron und resilient verarbeitet wird.

Hauptmerkmale:

  • Reagiert auf ein Ereignis, Ă€ndert es jedoch niemals.
  • FĂŒhrt nur In-Process-Operationen aus, die mit der Konsistenz der DomĂ€ne zusammenhĂ€ngen.
  • Stellt sicher, dass alles innerhalb derselben Transaktion ausgefĂŒhrt wird.

Um einen neuen DomĂ€nen-Ereignis-Handler zu erstellen, fĂŒhren Sie einfach den Befehl aus:

lino event-handler new

Der CLI-Assistent wird Folgendes abfragen:

  • Service – Der Service, in dem der Ereignis-Handler erstellt wird.
  • Modul – Das Modul, in dem der Ereignis-Handler erstellt wird (nur in modularen Services).
  • EntitĂ€t – Die EntitĂ€t, in der der Ereignis-Handler erstellt wird.
  • Ereignistyp – DomĂ€nenereignis oder Integrationsereignis.
  • Ereignis – Das zu konsumierende Ereignis.
  • Name des Ereignis-Handlers – Der Name, der mit der EntitĂ€t und dem DomĂ€nenereignis verknĂŒpft wird.

Beispiel

Beim Erstellen des DomĂ€nen-Ereignis-Handlers UserCreated, der mit der EntitĂ€t User und dem Ereignis UserCreatedDomainEvent verknĂŒpft ist, erstellt das System automatisch einen Ereignis-Handler mit dem Namen UserCreatedDomainEventHandler.

Von Lino generierte Struktur:

MyApp/
└── src/
    └── Services/
        └── MyService/
            └── Application/
                ├── MyApp.MyService.Application.csproj
                └── UseCases/
                    └── Users/
                        ├── Commands/
                        ├── EventHandlers/
                        │   └── Domain/
                        │       └── UserCreatedDomainEventHandler.cs
                        ├── Logging/
                        ├── Queries/
                        └── Resources/

Integrationsereignisse

Integrationsereignisse sind Nachrichten, die darauf hinweisen, dass etwas Wichtiges passiert ist, und die mit externen Systemen oder anderen Microservices geteilt werden mĂŒssen.

Im Gegensatz zu DomÀnenereignissen besteht hier das Ziel in der Kommunikation zwischen Systemen und der Synchronisation von ZustÀnden.

Wann ein Integrationsereignis erstellen:

  • Wenn eine Änderung in Ihrem System in einem anderen System widergespiegelt werden muss.
  • Wenn Ihr Microservice Änderungen veröffentlichen muss, damit andere Microservices darauf reagieren können.

Hauptunterschiede zwischen Domain Events und Integration Events:

Aspekt DomÀnenereignis Integrationsereignis
Zielgruppe Intern Extern
Kopplung Niedrig (intern) Notwendig (zwischen Systemen)
Verarbeitungszeit Sofort Kann asynchron sein, mit Liefergarantie
Erforderliche Persistenz Nicht erforderlich Ja (fĂŒr ZuverlĂ€ssigkeit und Resilienz)

In Lino ist das Erstellen eines neuen Integrationsereignisses einfach. Sie können ausfĂŒhren:

lino event new

Der CLI-Assistent fragt nach:

  • Service – Der Service, in dem das Ereignis erstellt wird.
  • Modul – Das Modul, in dem das Ereignis erstellt wird (nur fĂŒr modulare Services).
  • EntitĂ€t – Die EntitĂ€t, in der das Ereignis erstellt / zugeordnet wird.
  • Ereignistyp – DomĂ€nenereignis oder Integrationsereignis.
  • Ereignisname – Name, der fĂŒr das Integrationsereignis verwendet wird und mit der EntitĂ€t verknĂŒpft ist.

Beispiel

Wenn das Integrationsereignis UserCreated mit der EntitĂ€t User erstellt wird, erstellt das System automatisch ein Ereignis mit dem Namen UserCreatedIntegrationEvent. Dieser Name macht fĂŒr jeden Teil des Systems, der das Ereignis konsumiert, deutlich, dass die Benutzererstellung bereits abgeschlossen ist.

Von Lino generierte Struktur:

MyApp/
└── src/
    └── Services/
        └── MyService/
            └── IntegrationEvents/
                ├── MyApp.MyService.IntegrationEvents.csproj
                └── Users/
                    └── UserCreatedIntegrationEvent.cs

Integrations-Event-Handler

Ein Integration Event Handler ist eine Klasse, die dafĂŒr verantwortlich ist, ein Integrationsereignis zu konsumieren, das normalerweise von einem anderen Service oder Kontext veröffentlicht wird, und anschließend spezifische Aktionen in der eigenen DomĂ€ne auszufĂŒhren.

Diese Handler empfangen Ereignisse ĂŒber Messaging-Systeme (wie RabbitMQ, Kafka, Azure Service Bus usw.), meist in Kombination mit dem Outbox-Pattern, das eine zuverlĂ€ssige Zustellung und asynchrone Verarbeitung sicherstellt.

Zum Beispiel kann, wenn ein UserCreated-Ereignis von einem Identity-Service veröffentlicht wird, der entsprechende Handler in einem anderen Kontext reagieren, indem er eine Willkommens-E-Mail sendet oder externe APIs aufruft. Diese VorgĂ€nge können langsamer oder fehleranfĂ€llig sein, beeintrĂ€chtigen jedoch die interne Konsistenz der Anwendung nicht, da sie außerhalb der Haupttransaktion behandelt werden.

Hauptmerkmale:

  • Reagiert auf Ereignisse, die geschĂ€ftlich relevante Fakten fĂŒr andere Kontexte darstellen.
  • FĂŒhrt VorgĂ€nge aus, die langsam oder extern sein können (z. B. E-Mail-Versand, API-Aufrufe).
  • Wird asynchron und resilient verarbeitet, oft mit Wiederholungen und Monitoring.
  • Stellt sicher, dass externe Fehler die ursprĂŒngliche DomĂ€nentransaktion nicht beeinflussen.
  • Erleichtert die Integration zwischen Bounded Contexts und verteilten Systemen.

Um einen neuen Integrations-Event-Handler zu erstellen, fĂŒhren Sie einfach folgenden Befehl aus:

lino event-handler

Der CLI-Assistent fragt Folgendes ab:

  • Service – Der Service, in dem der Event-Handler erstellt wird.
  • Modul – Das Modul, in dem der Event-Handler erstellt wird (nur in modularen Services).
  • EntitĂ€t – Die EntitĂ€t, in der der Event-Handler erstellt wird.
  • Ereignistyp – DomĂ€nenereignis oder Integrationsereignis.
  • Service – Der Service, in dem das zu konsumierende Ereignis existiert.
  • Modul – Das Modul, in dem das zu konsumierende Ereignis existiert (nur in modularen Services).
  • EntitĂ€t – Die EntitĂ€t, in der das zu konsumierende Ereignis existiert.
  • Ereignis – Das zu konsumierende Ereignis.
  • Name des Event-Handlers – Name, der mit der EntitĂ€t und dem Integrationsereignis verknĂŒpft wird.

Beispiel

Beim Erstellen des Integrations-Event-Handlers SendEmailOnUserCreated, der mit der EntitĂ€t User und dem Ereignis UserCreatedIntegrationEvent verknĂŒpft ist, erstellt das System automatisch einen Event-Handler mit dem Namen SendEmailOnUserCreatedIntegrationEventHandler.

Von Lino generierte Struktur:

MyApp/
└── src/
    └── Services/
        └── MyService/
            └── Application/
                ├── MyApp.MyService.Application.csproj
                └── UseCases/
                    └── Users/
                        ├── Commands/
                        ├── EventHandlers/
                        │   └── Integration/
                        │       └── SendEmailOnUserCreatedIntegrationEventHandler.cs
                        ├── Logging/
                        ├── Queries/
                        └── Resources/
Ein unbehandelter Fehler ist aufgetreten. Aktualisieren 🗙