Événements asynchrones

Comment fonctionnent les flux asynchrones basés sur les événements : publication, consommation et traitement entre microservices via l'Event Bus.

Qu’est-ce qu’un flux asynchrone basé sur les événements

Dans un flux asynchrone, un service publie un événement pour signaler que quelque chose s’est produit, et d’autres services réagissent à cet événement sans que le publicateur ait besoin d’attendre une réponse. Il n’existe aucune connexion directe entre celui qui produit l’événement et celui qui le consomme.

Ce modèle est fondamental dans les architectures distribuées car il permet un découplage temporel : les services n’ont pas besoin d’être disponibles en même temps pour communiquer.

Différence avec la communication synchrone

AspectSynchroneAsynchrone (événements)
CouplageL’émetteur connaît le récepteurL’émetteur ignore qui consomme
DisponibilitéLes deux doivent être actifsLe consommateur peut traiter plus tard
RéponseImmédiateAucune réponse directe
ScalabilitéLimitée par le récepteur le plus lentChaque consommateur scale indépendamment
ComplexitéMoindrePlus élevée (ordre, doublons, cohérence)

Anatomie d’un événement

Un événement bien défini contient :

  • Type : nom qui identifie ce qui s’est produit (OrderPlaced, PaymentCompleted)
  • Payload : données pertinentes du fait (ID de la commande, montant, timestamp)
  • Metadata : informations de traçabilité (correlationId, timestamp, source)
  • Version : pour gérer l’évolution du schéma
{
  "type": "OrderPlaced",
  "version": "1.0",
  "timestamp": "2024-01-15T10:30:00Z",
  "correlationId": "abc-123-def",
  "source": "ms-orders",
  "payload": {
    "orderId": "order-456",
    "customerId": "cust-789",
    "totalAmount": 150.00,
    "items": [
      { "productId": "prod-001", "quantity": 2 }
    ]
  }
}

Le cycle complet d’un événement

sequenceDiagram
    participant MS1 as Microservicio Origen
    participant EB as Event Bus
    participant MS2 as Consumidor A
    participant MS3 as Consumidor B
    participant MS4 as Consumidor C

    MS1->>EB: Publicar evento (OrderPlaced)
    Note over MS1: El publicador continúa su trabajo

    EB->>MS2: Entregar evento
    EB->>MS3: Entregar evento
    EB->>MS4: Entregar evento

    MS2->>MS2: Actualizar inventario
    MS3->>MS3: Enviar notificación
    MS4->>MS4: Registrar analytics

Étape 1 : Publication

Le microservice d’origine achève son opération principale (par exemple, créer une commande) et publie un événement sur l’Event Bus. Une fois publié, le service n’attend pas que quiconque le traite.

Étape 2 : Distribution

L’Event Bus reçoit l’événement et le distribue à tous les consommateurs abonnés. Selon la technologie (Kafka, RabbitMQ, SNS/SQS), la distribution peut être :

  • Fan-out : tous les abonnés reçoivent une copie
  • Concurrence : un seul consommateur du groupe traite chaque message
  • Combinaison : fan-out entre les groupes, concurrence au sein de chaque groupe

Étape 3 : Consommation

Chaque consommateur reçoit l’événement et exécute sa logique de manière indépendante. Un consommateur lent n’affecte pas les autres.

Étape 4 : Confirmation

Le consommateur confirme (acknowledge) qu’il a correctement traité l’événement. En cas d’échec, l’Event Bus peut réessayer la livraison.

Modèles de publication

Publier après la persistance

Le service enregistre d’abord dans sa base de données, puis publie l’événement. C’est simple, mais cela comporte un risque : si la publication échoue après la persistance, l’événement est perdu.

Outbox Pattern

Le service enregistre l’événement dans une table outbox au sein de la même transaction que l’opération métier. Un processus distinct lit la table outbox et publie les événements sur le bus. Cela garantit la cohérence entre l’opération et la publication.

Event Sourcing

Au lieu de sauvegarder l’état actuel, on sauvegarde tous les événements qui ont produit cet état. La publication est inhérente au modèle.

Défis des flux asynchrones

Ordre des événements

Les événements peuvent arriver dans un ordre différent de celui dans lequel ils ont été publiés. Les consommateurs doivent être capables de gérer cela, soit en réordonnant, soit en tolérant le désordre.

Événements dupliqués

L’Event Bus peut livrer le même événement plusieurs fois (at-least-once delivery). Les consommateurs doivent être idempotents : traiter deux fois le même événement doit produire le même résultat que de le traiter une seule fois.

Cohérence à terme

Les données entre services ne sont pas synchronisées instantanément. Après la publication d’un événement, un certain temps peut s’écouler avant que tous les consommateurs ne reflètent le changement. Le système doit être conçu pour tolérer cette fenêtre d’incohérence.

Observabilité

Suivre un flux asynchrone est plus difficile qu’un flux synchrone. Le correlationId est essentiel pour pouvoir suivre la chaîne d’événements à travers de multiples services.

Quand utiliser les événements asynchrones

Ils conviennent lorsque :

  • Plusieurs services doivent réagir au même fait
  • Aucune réponse immédiate n’est nécessaire
  • On souhaite découpler les services pour les faire évoluer indépendamment
  • Le processus peut tolérer une cohérence à terme

Ils ne conviennent pas lorsque :

  • Une réponse immédiate est nécessaire pour l’utilisateur
  • L’opération exige une cohérence forte entre les services
  • La complexité ajoutée ne se justifie pas par le volume ou les exigences

Résumé

Les flux asynchrones basés sur les événements permettent aux services de communiquer sans couplage direct. Le publicateur ne connaît pas les consommateurs, et chaque consommateur traite à son propre rythme. Cela apporte scalabilité et résilience, mais introduit des défis d’ordre, de doublons et de cohérence qui doivent être abordés avec des modèles tels que l’idempotence, l’outbox et la traçabilité distribuée.