Skip to main content
Version: Next

Domain Events

Files Referenced in this Document

Table of Contents​

  1. Introduction
  2. MyEntityNameEto Event Transfer Object
  3. MyEntityNameEventHandler Event Handler
  4. Domain Event Publishing Mechanism
  5. Advantages of Event-Driven Architecture
  6. Summary and Development Guide

Introduction​

This document comprehensively explains the event-driven mechanism in the MyEntityName domain. Based on a distributed event bus, this mechanism implements loosely coupled communication across service boundaries by defining Event Transfer Objects (ETOs) and event handlers. The document details event definition, handling, publishing flows, and advantages in ensuring eventual system consistency.

MyEntityNameEto Event Transfer Object​

MyEntityNameEto is the Event Transfer Object (ETO) for the MyEntityName domain, used to transfer data related to the MyEntityName entity across service boundaries in a distributed system.

Key features of this object include:

  • Immutability: Its Name property is initialized only in the constructor and is read-only externally, ensuring integrity of event data during transmission.
  • Serialization Support: The class is marked with [Serializable], enabling serialization and deserialization over the network, which is the foundation for distributed event transmission.
  • Single Data Carrier: Currently contains only the Name property as the core information to broadcast when the event occurs.

This design pattern ensures clarity, stability, and transportability of event data.

Section sources

MyEntityNameEventHandler Event Handler​

MyEntityNameEventHandler is the concrete implementation class responsible for handling MyEntityNameEto events.

Key implementation details of this handler:

  • Event Subscription: By implementing the IDistributedEventHandler<MyEntityNameEto> interface, this handler automatically subscribes to distributed events of type MyEntityNameEto. Its HandleEventAsync method is called when such events are published on the event bus.
  • Lifecycle Management: Implements ITransientDependency interface, indicating a transient lifecycle. A new instance is created for each event processing, ensuring independence and thread safety.
  • Async Processing: HandleEventAsync uses an asynchronous pattern, meeting modern application requirements for high concurrency and non-blocking I/O.
  • Empty Implementation Status: Currently, the HandleEventAsync body is empty (return Task.CompletedTask;), providing an extension point for developers. Developers should add specific business logic here, such as:
    • Sending notifications (e.g., email, SMS)
    • Updating caches to maintain data consistency
    • Triggering downstream service business processes
    • Recording audit logs

Section sources

Domain Event Publishing Mechanism​

Domain event publishing follows standard patterns in Domain-Driven Design (DDD), mainly involving two core steps: Defining events in the Aggregate Root and Publishing events by Domain Services.

  1. Defining events in the Aggregate Root: Although not directly shown in current code, standard practice involves calling AddLocalEvent() or AddEvent() methods within business methods of the MyEntityName aggregate root (inheriting from FullAuditedAggregateRoot<Guid>) when important business state changes occur, adding a MyEntityNameEto event instance to the aggregate root's event collection. For example, after the Update method successfully modifies the entity, an event can be added to announce "MyEntityName Updated".

  2. Publishing events by Domain Services: When changes to the aggregate root are persisted (e.g., via repository Save or Update methods), the framework automatically publishes accumulated domain events to the event bus. In distributed scenarios, these events are serialized and sent to message queues (like RabbitMQ, Kafka), triggering all handlers subscribed to the event (like MyEntityNameEventHandler).

This mechanism decouples business logic execution from event publishing, ensuring purity of core business code.

Section sources

Advantages of Event-Driven Architecture​

Adopting an event-driven mechanism brings significant advantages to the system, the core being Eventual Consistency.

  • Eventual Consistency: In distributed systems, strong consistency (ACID) is often costly and difficult to achieve. Event-driven architecture implements eventual consistency through the "commit local transaction first, then publish event" pattern. This means that after a service completes its local data update, it immediately confirms the operation and asynchronously notifies other services. Although other services' data updates will have a short delay, the system will eventually reach a consistent state. This pattern greatly improves system response speed and availability.
  • Loose Coupling: Event publishers (like MyEntityName aggregate root) do not need to know who consumes the event, nor interact directly with consumers (like MyEntityNameEventHandler). This allows system components to be developed, deployed, and scaled independently.
  • Extensibility: New event handlers can be easily added to respond to the same event without modifying publisher code, facilitating feature extension.
  • Traceability: Events themselves record important state changes occurring in the system, providing valuable data for auditing, monitoring, and troubleshooting.

Diagram sources

Summary and Development Guide​

This document detailed the event-driven mechanism in the MyEntityName domain. MyEntityNameEto as an immutable, serializable data carrier, and MyEntityNameEventHandler as the event consumer, together constitute the core of event processing.

Development Guide:

  1. Publish Event: Create a MyEntityNameEto instance and call the AddEvent() method within business methods of the MyEntityName aggregate root when key state changes occur.
  2. Handle Event: Fill in actual business logic in the HandleEventAsync method of MyEntityNameEventHandler. Note exception handling and consider idempotency, as events might be consumed repeatedly.
  3. Leverage Advantages: Fully utilize the eventual consistency and loose coupling features brought by event-driven design to build highly available, scalable distributed systems.

Section sources