Simulateur d'Événements
Concevez et tracez des flux d'événements entre microservices — de la publication à la consommation et aux réactions en chaîne.
Objectif
Dans ce laboratoire, vous allez concevoir des flux d’événements entre microservices, tracer leur parcours complet et anticiper les problèmes qui peuvent survenir dans une architecture event-driven.
Les événements sont le système nerveux d’une architecture distribuée. Comprendre comment ils circulent est fondamental pour concevoir des systèmes découplés et résilients.
Concepts préalables
Avant de commencer, assurez-vous de bien comprendre la différence entre :
| Concept | Description | Exemple |
|---|---|---|
| Commande | Requête pour faire quelque chose | CreateOrder |
| Événement | Notification de quelque chose qui s’est déjà produit | OrderCreated |
| Query | Requête d’information | GetOrderStatus |
Les événements sont des faits immuables — quelque chose qui s’est déjà produit et qui ne peut pas être annulé. Les commandes sont des intentions — elles peuvent être rejetées.
Exercice 1 : Concevoir un flux d’événements
Scénario
Un utilisateur achète un produit sur votre e-commerce. Concevez le flux complet d’événements depuis le clic sur « Acheter » jusqu’à la réception de la confirmation.
Services impliqués
- Service de Commandes : crée et gère les commandes
- Service d’Inventaire : réserve et décrémente le stock
- Service de Paiements : traite l’encaissement
- Service de Notifications : envoie des emails et des notifications push
- Service d’Analytics : enregistre les métriques métier
Votre tâche
Complétez le diagramme d’événements :
Usuario hace clic en "Comprar"
│
▼
[Servicio de Órdenes]
│ publica: OrderCreated { orderId, userId, items, total }
│
├──► [Servicio de Inventario]
│ consume: OrderCreated
│ acción: reservar stock
│ publica: _______________
│
├──► [Servicio de Pagos]
│ consume: _______________
│ acción: procesar cobro
│ publica: _______________
│
├──► [Servicio de Notificaciones]
│ consume: _______________
│ acción: _______________
│
└──► [Servicio de Analytics]
consume: _______________
acción: _______________
Solution
Voir le flux complet
Usuario hace clic en "Comprar"
│
▼
[Servicio de Órdenes]
│ publica: OrderCreated { orderId, userId, items, total }
│
├──► [Servicio de Inventario]
│ consume: OrderCreated
│ acción: reservar stock para los items
│ publica: StockReserved { orderId, items }
│ o StockInsufficient { orderId, items }
│
├──► [Servicio de Pagos]
│ consume: StockReserved
│ acción: procesar cobro con el proveedor
│ publica: PaymentCompleted { orderId, transactionId }
│ o PaymentFailed { orderId, reason }
│
├──► [Servicio de Notificaciones]
│ consume: PaymentCompleted
│ acción: enviar email de confirmación al usuario
│ consume: PaymentFailed
│ acción: enviar email de fallo al usuario
│
└──► [Servicio de Analytics]
consume: OrderCreated, StockReserved, PaymentCompleted
acción: registrar métricas de conversión y revenue
Exercice 2 : Gérer le chemin malheureux
Scénario
Que se passe-t-il lorsque quelque chose échoue au milieu du flux ? Concevez les compensations.
Cas 1 : Le stock a été réservé mais le paiement a échoué
OrderCreated → StockReserved → PaymentFailed
│
▼
¿Qué pasa ahora?
Votre tâche : Quel événement le service de paiements doit-il publier ? Qui le consomme ? Quelle action prend-il ?
Voir la solution
PaymentFailed { orderId, reason }
│
├──► [Servicio de Inventario]
│ consume: PaymentFailed
│ acción: liberar stock reservado
│ publica: StockReleased { orderId, items }
│
├──► [Servicio de Órdenes]
│ consume: PaymentFailed
│ acción: marcar orden como fallida
│ publica: OrderCancelled { orderId, reason }
│
└──► [Servicio de Notificaciones]
consume: OrderCancelled
acción: notificar al usuario que el pago falló
C’est le pattern Saga par chorégraphie : chaque service réagit aux événements et exécute des compensations lorsque quelque chose échoue. Il n’y a pas d’orchestrateur central.
Cas 2 : Le service d’inventaire est hors service
OrderCreated → [Inventario: CAÍDO] → ???
Votre tâche : Que devient l’événement OrderCreated ? Est-il perdu ? Est-il réessayé ?
Voir la solution
Si vous utilisez un message broker avec des files d’attente durables (RabbitMQ, Kafka) :
- L’événement
OrderCreatedreste dans la file d’attente en attente - Lorsque le service d’inventaire revient, il consomme les événements en attente
- Le traitement se poursuit normalement (avec du délai)
Point clé : La file d’attente agit comme un buffer temporaire. L’événement n’est pas perdu tant que la file est durable et que les messages sont persistants.
À considérer : Si le service reste hors service longtemps, la file grandit. Vous avez besoin de :
- Alertes sur la taille de la file
- TTL sur les messages pour éviter de traiter des événements trop anciens
- Logique de compensation si l’événement n’est plus pertinent
Exercice 3 : Ordonnancement des événements
Le problème
Deux événements arrivent au service d’inventaire :
StockUpdated { productId: "ABC", quantity: 100 }(timestamp : 10:00:01)StockUpdated { productId: "ABC", quantity: 50 }(timestamp : 10:00:00)
L’événement 2 a été publié en premier mais est arrivé après. Si vous traitez dans l’ordre d’arrivée, le stock reste à 50 (incorrect — il devrait être à 100).
Votre tâche
Comment garantissez-vous le bon ordre ? Évaluez ces stratégies :
| Stratégie | Avantages | Inconvénients |
|---|---|---|
| Trier par timestamp | Simple | Horloges non synchronisées entre services |
| Numéro de séquence | Ordre garanti | Nécessite une coordination entre les publishers |
| Partition par key | Ordre au sein de la partition | Limite le parallélisme |
| Version optimiste | Ne nécessite pas d’ordre global | Nécessite une logique de résolution de conflits |
Voir la recommandation
La stratégie la plus pratique dans la plupart des cas est la partition par key :
- Dans Kafka : utiliser
productIdcomme partition key - Tous les événements d’un même produit vont à la même partition
- Au sein d’une partition, l’ordre est garanti
- Différents produits sont traités en parallèle
Pour les cas où vous avez besoin d’un ordre global, utilisez un numéro de séquence généré par le publisher et rejetez les événements dont la séquence est inférieure à la dernière traitée.
Exercice 4 : Concevez votre propre flux
Votre tâche
Choisissez l’un de ces scénarios et concevez le flux complet d’événements :
Option A : Système de réservations d’hôtel
- Services : Réservations, Chambres, Paiements, Notifications
- Flux : l’utilisateur réserve → vérifier la disponibilité → encaisser → confirmer
Option B : Plateforme de livraison
- Services : Commandes, Restaurants, Livreurs, Suivi, Notifications
- Flux : l’utilisateur commande → le restaurant accepte → livreur assigné → livraison
Option C : Système d’abonnements
- Services : Utilisateurs, Abonnements, Paiements, Accès, Notifications
- Flux : l’utilisateur s’abonne → prélèvement récurrent → renouvellement/annulation
Pour chacun, définissez :
- Les événements principaux (chemin heureux)
- Les événements de compensation (chemin malheureux)
- Quel service publie et qui consomme chaque événement
- Comment vous gérez les échecs à chaque étape
Réflexion
- De combien d’événements avez-vous eu besoin pour un flux « simple » ?
- À quel point a-t-il été difficile de concevoir les compensations ?
- Préféreriez-vous un orchestrateur central (Saga orchestrée) ou une chorégraphie ?
- Comment déboggeriez-vous un problème dans un flux de plus de 5 événements ?
Les systèmes event-driven sont puissants mais complexes. La clé est de concevoir les flux avant d’écrire du code — et de toujours penser à ce qui se passe quand quelque chose échoue.