Travailler avec les événements

Dans les systĂšmes modernes, suivant les bonnes pratiques d’architecture telles que DDD (Domain-Driven Design) et Clean Architecture, les Ă©vĂ©nements sont des mĂ©canismes fondamentaux pour modĂ©liser les changements d’état et la communication asynchrone entre composants ou systĂšmes. Un Ă©vĂ©nement reprĂ©sente quelque chose qui s’est dĂ©jĂ  produit dans le domaine de l’application et qui peut intĂ©resser d’autres parties du systĂšme ou des services externes.

ÉvĂ©nements de Domaine

Les événements de domaine représentent des faits importants survenus dans le contexte de l'application. Ils sont générés et consommés en interne dans le systÚme, permettant la propagation des changements d'état de maniÚre découplée, c'est-à-dire sans que les objets aient besoin de se connaßtre directement.

Quand utiliser un ÉvĂ©nement de Domaine ?

  • Chaque fois qu'une opĂ©ration gĂ©nĂšre un changement significatif dans le domaine et qu'il est nĂ©cessaire de notifier ou d'activer d'autres parties du systĂšme.
  • Pour maintenir le modĂšle de domaine cohĂ©sif, permettant Ă  diffĂ©rents processus d'ĂȘtre dĂ©clenchĂ©s sans crĂ©er de dĂ©pendances directes entre les modules ou services.

Dans Lino, créer un nouvel événement de domaine est simple. Vous pouvez exécuter :

lino event new

L'assistant CLI demandera :

  • Service – Le service dans lequel l'Ă©vĂ©nement sera créé.
  • Module – Le module dans lequel l'Ă©vĂ©nement sera créé (uniquement pour les services modulaires).
  • EntitĂ© – L'entitĂ© dans laquelle l'Ă©vĂ©nement sera créé/associĂ©.
  • Type d'Ă©vĂ©nement – ÉvĂ©nement de domaine ou Ă©vĂ©nement d'intĂ©gration.
  • Nom de l'Ă©vĂ©nement – Nom utilisĂ© dans le domaine, associĂ© Ă  l'entitĂ©.

Exemple

En créant l'événement de domaine UserCreated associé à l'entité User, le systÚme crée automatiquement un événement nommé UserCreatedDomainEvent. Ce nom indique clairement à toute partie du systÚme consommant l'événement que l'action de création de l'utilisateur a déjà été effectuée.

Structure générée par Lino :

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

Gestionnaires d'ÉvĂ©nements de Domaine

Un Domain Event Handler est une classe responsable de rĂ©agir Ă  un ÉvĂ©nement de Domaine, exĂ©cutant des actions liĂ©es Ă  l'Ă©tat interne de l'application, toujours dans le mĂȘme contexte transactionnel.

L'objectif principal de ces gestionnaires est de maintenir le systÚme cohésif et découplé, permettant l'application de rÚgles supplémentaires sans surcharger la logique centrale de l'entité ou de l'agrégat.

Par exemple, aprĂšs la crĂ©ation d'un User, il peut ĂȘtre nĂ©cessaire de mettre Ă  jour les statistiques, gĂ©nĂ©rer un journal interne ou notifier un autre agrĂ©gat. Ces actions ont du sens dans le domaine et peuvent se produire de maniĂšre synchrone, garantissant une cohĂ©rence immĂ©diate.

Cependant, les opĂ©rations qui dĂ©pendent de ressources externes — telles que l'envoi d'e-mails ou les appels Ă  des API tierces — ne doivent pas ĂȘtre exĂ©cutĂ©es directement Ă  partir des Ă©vĂ©nements de domaine, car cela lierait la transaction Ă  des tĂąches lentes ou instables. Dans ces cas, le domaine peut gĂ©nĂ©rer un Ă©vĂ©nement d'intĂ©gration (enregistrĂ© dans l'Outbox), qui sera traitĂ© ultĂ©rieurement de maniĂšre asynchrone et rĂ©siliente.

Caractéristiques principales :

  • RĂ©agit Ă  un Ă©vĂ©nement mais ne le modifie jamais.
  • ExĂ©cute uniquement des opĂ©rations in-process liĂ©es Ă  la cohĂ©rence du domaine.
  • Garantit que tout s'exĂ©cute dans la mĂȘme transaction.

Pour créer un nouveau gestionnaire d'événements de domaine, il suffit d'exécuter la commande :

lino event-handler new

L'assistant CLI demandera :

  • Service – Service dans lequel le gestionnaire d'Ă©vĂ©nements sera créé.
  • Module – Module dans lequel le gestionnaire d'Ă©vĂ©nements sera créé (uniquement dans les services modulaires).
  • EntitĂ© – EntitĂ© dans laquelle le gestionnaire d'Ă©vĂ©nements sera créé.
  • Type d'Ă©vĂ©nement – ÉvĂ©nement de domaine ou Ă©vĂ©nement d'intĂ©gration.
  • ÉvĂ©nement – ÉvĂ©nement qui sera consommĂ©.
  • Nom du gestionnaire d'Ă©vĂ©nements – Nom utilisĂ© qui sera associĂ© Ă  l'entitĂ© et Ă  l'Ă©vĂ©nement de domaine.

Exemple

En créant le gestionnaire d'événements de domaine UserCreated associé à l'entité User et à l'événement UserCreatedDomainEvent, le systÚme crée automatiquement un gestionnaire d'événements nommé UserCreatedDomainEventHandler.

Structure générée par Lino :

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

ÉvĂ©nements d'IntĂ©gration

Les Ă©vĂ©nements d'intĂ©gration sont des messages indiquant qu'un Ă©vĂ©nement important s'est produit et doivent ĂȘtre partagĂ©s avec des systĂšmes externes ou d'autres microservices.

Contrairement aux événements de domaine, l'objectif ici est la communication entre systÚmes et la synchronisation des états.

Quand crĂ©er un ÉvĂ©nement d'IntĂ©gration :

  • Lorsque un changement dans votre systĂšme doit ĂȘtre reflĂ©tĂ© dans un autre systĂšme.
  • Lorsque votre microservice doit publier des changements afin que d'autres microservices puissent rĂ©agir.

Principales différences entre les Domain Events et les Integration Events :

Aspect ÉvĂ©nement de Domaine ÉvĂ©nement d'IntĂ©gration
Public cible Interne Externe
Couplage Faible (interne) Nécessaire (entre systÚmes)
Temps de traitement ImmĂ©diat Peut ĂȘtre asynchrone, avec garanties de livraison
Persistance requise Non obligatoire Oui (pour fiabilité et résilience)

Dans Lino, créer un nouvel événement d'intégration est simple. Vous pouvez exécuter :

lino event new

Le assistant CLI demandera :

  • Service – Le service dans lequel l'Ă©vĂ©nement sera créé.
  • Module – Le module dans lequel l'Ă©vĂ©nement sera créé (uniquement pour les services modulaires).
  • EntitĂ© – L'entitĂ© dans laquelle l'Ă©vĂ©nement sera créé / associĂ©.
  • Type d'Ă©vĂ©nement – ÉvĂ©nement de domaine ou Ă©vĂ©nement d'intĂ©gration.
  • Nom de l'Ă©vĂ©nement – Nom utilisĂ© pour l'Ă©vĂ©nement d'intĂ©gration, associĂ© Ă  l'entitĂ©.

Exemple

En créant l'événement d'intégration UserCreated associé à l'entité User, le systÚme crée automatiquement un événement nommé UserCreatedIntegrationEvent. Ce nom indique clairement à toute partie du systÚme consommant l'événement que l'action de création de l'utilisateur a déjà été effectuée.

Structure générée par Lino :

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

Gestionnaires d'ÉvĂ©nements d'IntĂ©gration

Un Integration Event Handler est une classe responsable de consommer un ÉvĂ©nement d'IntĂ©gration, gĂ©nĂ©ralement publiĂ© par un autre service ou contexte, puis d'exĂ©cuter des actions spĂ©cifiques dans son propre domaine.

Ces handlers reçoivent les événements via des mécanismes de messagerie (comme RabbitMQ, Kafka, Azure Service Bus, etc.), généralement en combinaison avec le pattern Outbox, qui garantit une livraison fiable et un traitement asynchrone.

Par exemple, lorsqu'un Ă©vĂ©nement UserCreated est publiĂ© par un service d'IdentitĂ©, le handler correspondant dans un autre contexte peut rĂ©agir en envoyant un e-mail de bienvenue ou en appelant des APIs externes. Ces opĂ©rations peuvent ĂȘtre plus lentes ou sujettes Ă  des erreurs, mais comme elles sont traitĂ©es en dehors de la transaction principale, elles ne compromettent pas la cohĂ©rence interne de l'application.

Caractéristiques principales :

  • RĂ©agit aux Ă©vĂ©nements reprĂ©sentant des faits mĂ©tier pertinents pour d'autres contextes.
  • ExĂ©cute des opĂ©rations pouvant ĂȘtre lentes ou externes (ex. : envoi d'e-mails, appels Ă  des APIs).
  • Est traitĂ© de maniĂšre asynchrone et rĂ©siliente, souvent avec des tentatives de reprise et de la surveillance.
  • Garantit que les Ă©checs externes n'affectent pas la transaction d'origine du domaine.
  • Facilite l'intĂ©gration entre les bounded contexts et les systĂšmes distribuĂ©s.

Pour créer un nouveau gestionnaire d'événements d'intégration, il suffit d'exécuter la commande :

lino event-handler

L'assistant CLI demandera :

  • Service – Le service dans lequel le gestionnaire d'Ă©vĂ©nements sera créé.
  • Module – Le module dans lequel le gestionnaire d'Ă©vĂ©nements sera créé (uniquement pour les services modulaires).
  • EntitĂ© – L'entitĂ© dans laquelle le gestionnaire d'Ă©vĂ©nements sera créé.
  • Type d'Ă©vĂ©nement – ÉvĂ©nement de domaine ou Ă©vĂ©nement d'intĂ©gration.
  • Service – Le service dans lequel existe l'Ă©vĂ©nement Ă  consommer.
  • Module – Le module dans lequel existe l'Ă©vĂ©nement Ă  consommer (uniquement pour les services modulaires).
  • EntitĂ© – L'entitĂ© dans laquelle existe l'Ă©vĂ©nement Ă  consommer.
  • ÉvĂ©nement – L'Ă©vĂ©nement qui sera consommĂ©.
  • Nom du gestionnaire d'Ă©vĂ©nement – Nom utilisĂ© qui sera associĂ© Ă  l'entitĂ© et Ă  l'Ă©vĂ©nement d'intĂ©gration.

Exemple

En créant le gestionnaire d'événement d'intégration SendEmailOnUserCreated associé à l'entité User et à l'événement UserCreatedIntegrationEvent, le systÚme crée automatiquement un gestionnaire d'événement nommé SendEmailOnUserCreatedIntegrationEventHandler.

Structure générée par Lino :

MyApp/
└── src/
    └── Services/
        └── MyService/
            └── Application/
                ├── MyApp.MyService.Application.csproj
                └── UseCases/
                    └── Users/
                        ├── Commands/
                        ├── EventHandlers/
                        │   └── Integration/
                        │       └── SendEmailOnUserCreatedIntegrationEventHandler.cs
                        ├── Logging/
                        ├── Queries/
                        └── Resources/
Une erreur non gérée est survenue. Rafraîchir 🗙