Démo
FrançaisEnglishEspañolDeutschItaliano

Une architecture pilotée par les événements - Partie 3

4 min de lecture

Romuald Texier-MarcadéIngénieur R&D chez Allo-Media / uh!ive

Dans ce nouvel article, parlons de l’implémentation concrète des principes fondamentaux de l’architecture pilotée par les événements.

Topologie

La topologie décrit la façon dont le bus est implémenté sur le broker de messages.

Comme broker de messages, nous avons choisi RabbitMQ pour sa fiabilité éprouvée et sa facilité d’utilisation.

Dans RabbitMQ, la topologie se met en place en instanciant des exchanges et des queues.

Les exchanges sont en quelque sorte des routeurs, et les applications clientes y bindent des queues, en s’abonnant à des routing keys précises, pour stocker leurs messages en attente de traitement. Une bonne pratique consiste à considérer les queues comme privées au service logique (mais partagées par les workers de ce service logique). Nous utilisons le nom du type de message comme routing key.

La topologie se compose de trois exchanges :

  • un exchange events fiable, avec :
    • des queues consommateurs persistantes (qui survivent aux redémarrages du broker et des services)
    • des messages persistants (qui survivent aux redémarrages du broker et des services)
    • l’ack du traitement des messages par les clients
    • la confirmation des messages par le broker (pour détecter au plus tôt les défaillances réseau transitoires)
    • un routage topic (pour permettre le monitoring par wildcards)
  • un exchange commands fiable, avec :
    • des queues consommateurs persistantes (qui survivent aux redémarrages du broker et des services)
    • des messages persistants (qui survivent aux redémarrages du broker et des services)
    • l’ack du traitement des messages par les clients
    • la confirmation des messages par le broker (pour détecter au plus tôt les défaillances réseau transitoires)
    • un routage topic
  • un exchange logs, avec :
    • pas de persistance (pour ne pas saturer la mémoire du broker si personne ne consomme les logs)
    • ni ack ni confirmation des messages (pour la vitesse)
  • le routage des dead letters : quand un message est définitivement rejeté, il est automatiquement routé vers le dead letter exchange.

Le résultat d’une commande est lui aussi envoyé sur l’exchange commands.

Les instances d’un même service logique sont appelées les workers de ce service, et elles partagent la même queue. Le broker garantit qu’un message est traité par un et un seul worker du pool attaché à la queue.

L’ack du traitement des messages par les clients est un mécanisme très utile pour garantir qu’aucune donnée n’est perdue (autrement dit, qu’un message est traité au moins une fois) et pour permettre un load balancing efficace. En effet, le broker ne retire pas un message de la queue tant que le worker qui l’a pris en charge ne lui a pas signalé qu’il a terminé. Pendant ce temps, le message est réservé. Si le worker tombe avant d’avoir acké, le message redevient disponible pour n’importe quel autre worker, ou pour le même quand il revient. De plus, le broker sait à tout moment quels workers sont occupés et lesquels sont libres, ce qui lui permet de mieux répartir la charge entre eux.

Notez qu’il s’agit de la topologie de base. Comme la topologie est créée par les services eux-mêmes et non par une configuration centrale, ils peuvent l’étendre localement (c’est-à-dire de leur côté) selon leurs besoins. Cela veut dire aussi qu’ils doivent tous respecter la topologie de base décrite ci-dessus pour rejoindre le bus.

Comportements

La topologie décrit comment le broker route les messages et les garanties qu’il doit apporter.

L’EDA impose aussi aux services d’implémenter quelques règles de base pour garantir fiabilité et performance :

  • un message doit être acké une fois complètement traité, et jamais avant ;
  • le service doit garder en cache les messages envoyés jusqu’à ce que le broker les confirme, et les renvoyer sinon ;
  • le service doit se reconnecter automatiquement au broker en cas de déconnexion, sans perdre son cache ;
  • en cas d’échec inattendu pendant le traitement d’un message, le service doit le remettre en queue une fois avant de le rejeter définitivement ;
  • le service doit intercepter les erreurs irrécupérables (messages invalides, données incohérentes…), les loguer et acker le message fautif, pour qu’il ne soit ni remis en queue ni routé vers les dead letters.

Framework et outils

Pour éviter de dupliquer du code, nous avons développé des mini-frameworks (en Python, Elixir et Rust) qui implémentent cette topologie de base et tous les comportements attendus des services. Nous en parlerons dans le prochain article : Framework et outils !

Mots-clésAI algorithmsAllo-MediaanonymizeAPIaudiobusinessesconversationscustomersindexnamed entitiesNLPphonepipelinequalifysemantic tagstag transcriptstranscribeUIvalue chain

Partager

Articles similaires

Tous les articles