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/
