Une architecture pilotée par les événements – Partie 2

Dans le poste précédent de cette série, nous avons expliqué pourquoi nous avons abandonné notre ancienne architecture basée sur des services REST synchrones pour une architecture événementielle totalement asynchrone.

Aujourd’hui, nous abordons les principes de conception fondamentaux qui ont joué un rôle crucial dans la réussite de cette entreprise.

Services aux entreprises et services de traitement des données

Nous faisons une distinction entre Business Services et Data Processing Services  ; (alias services utilitaires) afin de séparer clairement la logique commerciale de la complexité du traitement des données.

Services de traitement des données

Les services de traitement des données sont censés être purstateless des services qui fournissent une sorte de traitement algorithmique des données (calculs, transformations…). En outre, ils ne dépendent pas du contexte : ils ne doivent pas dépendre de règles commerciales, d’hypothèses ou de sources de données externes. Tout ce dont ils ont besoin pour effectuer leur traitement doit se trouver dans le message qu’ils reçoivent. Ils ne doivent pas avoir à interroger un niveau pour obtenir davantage de données. Les services de traitement des données sont en quelque sorte des bibliothèques universelles et peuvent même être fournis par des niveaux.

Exemples de services de traitement des données :

  • Un service de conversion de la parole en texte a de nombreuses applications. Il n’a besoin que de données audio et d’une référence linguistique. Il n’a pas besoin de conserver de données.
  • Un service de clouage d’images. Il ne prend en entrée qu’une image et les dimensions des cibles. Il n’a pas d’effets secondaires et peut être utilisé dans de nombreuses entreprises.

Services aux entreprises

Les services commerciaux mettent en œuvre les flux de travail des clients et se concentrent uniquement sur les règles et les exigences commerciales afin d’orchestrer et de mettre en œuvre la valeur ajoutée sur les données audio et les données de nos clients. Ils utilisent les services de traitement des données comme une bibliothèque pour cela. Ils nous sont très spécifiques : vous ne voudriez jamais externaliser vos services commerciaux.

Les services d’entreprise conservent les données qu’ils produisent et constituent leur unique source de vérité.

Les services d’entreprise construisent et maintiennent leur propre configuration client à partir d’événements sur le bus.

Exemples de services aux entreprises :

  • Chez Allo-Media, nous disposons d’un service d’entreprise pour étiqueter les appels entrants. Il écoute les transcriptions des appels et publie des étiquettes de qualification. Il connaît les besoins de nos clients et marque les appels en conséquence. Il conserve les étiquettes et est la seule source de confiance pour eux.
  • Un service de panier d’achat pour une boutique en ligne. Pour chaque utilisateur en ligne, il maintient l’état de son panier en écoutant les événements de l’interface utilisateur comme ItemSelectedItemRemoved ou les événements de stock comme ItemStockLeft….

Tous les services doivent être idempotents, c’est-à-dire que s’ils reçoivent deux fois exactement le même message, ils doivent se comporter de manière identique et produire les mêmes résultats.

Événements, commandes et résultats

De la même manière que nous avons deux types de services différents, nous avons deux types de messages différents :  Commandes (et leurs résultats) et Evènements.

Evénements

Les événements sont des messages commerciaux publiés sur le bus par les services commerciaux et indiquant au monde ce qui s’est passé.

Un service commercial est propriétaire du type d’événements qu’il émet. Il ne sait rien des services qui les traiteront. Il s’abonne aux types d’événements dont il a besoin, mais ne sait rien de leur origine.

Un type d’événement définit la signification des événements de ce type et leur schéma de données. Ils doivent être documentés.

Le type de message d’événement réel est donné par son nom (également appelé routing key car il est utilisé par le routage de l’abonnement). Le nom du type d’événement doit se présenter sous la forme SubjectPastParticiple. Par exemple, ConversationStartedCustomerCreatedShoppingCartValidated… Si vous n’êtes pas capable de donner immédiatement un nom à votre type d’événement, c’est qu’il n’est pas bien défini, ou qu’il ne s’agit pas d’un événement. Peut-être devez-vous affiner votre service ou le scinder, car vous n’avez peut-être pas analysé votre chaîne de valeur suffisamment en profondeur ?

Commandes et résultats

Les commandes sont des messages utilitaires consommés par les services de traitement des données. Imaginez une commande que vous transmettez à un fournisseur. Vous ne savez pas qui l’exécutera, vous ne savez pas non plus comment et quand, mais vous recevrez ce que vous voulez dans votre boîte aux lettres un peu plus tard.

Un service de traitement des données est propriétaire des types de commandes qu’il consomme et de leurs résultats. Une commande est toujours adressée au service logique qui la possède.

Un type de commande définit la signification de la commande, son schéma de données et son schéma de données de résultat. Il doit être documenté.

Le type de message de commande est indiqué par son nom. Il se présente sous la forme VerbObject. Par exemple: AnnotateTextTranscribeAudio… Comme les commandes sont adressées à un service logique particulier, la clé de routage d’une commande se présente sous la forme nom_du_service_logique.nom_de_la&commande. Par exemple: asr.TranscribeAudio.

La commande contient l' »adresse » de retour à laquelle le résultat doit être envoyé, ainsi qu’une référence définie par l’expéditeur qui est renvoyée telle quelle, en même temps que le résultat de la commande. Cette référence s’appelle l’identificateur de corrélation et elle est très importante pour l’expéditeur : comme toutes les communications sont asynchrones, le service qui demande la commande a besoin d’un moyen de réconcilier le résultat reçu avec la demande initiale qu’il a faite.

Un résultat est un message associé et spécifique à chaque commande et qui contient le résultat du processus – qui peut être une réussite ou une erreur – et l’identifiant de corrélation. Les messages de résultat ne peuvent exister sans commande préalable.

Les résultats d’erreur sont attendus et documentés : il s’agit d’erreurs « normales » et non de rapports de bogues. Les exceptions de bogues ne doivent pas renvoyer de résultat d’erreur. En cas d’erreur inattendue, le service demande à la commande d’entrée d’être réessayée une fois, et si un deuxième essai soulève à nouveau une erreur inattendue, le message est refusé et placé dans la file d’attente des lettres mortes en vue d’une enquête. Les exceptions sont toujours enregistrées.

Journaux

Nous pouvons également avoir des messages de journalisation pour collecter facilement les journaux d’application.

Tous les messages qui « cascadent » à partir du même événement source partagent un identifiant commun, appelé l' »identifiant de conversation », qui possède les propriétés suivantes :

  • il est unique dans le temps ;
  • il est créé par un Event  ; (jamais par des Commandes) qui est publié pour des raisons externes au bus et non en réaction à d’autres Events ; nous appelons ce Event l’événement initial.
  • Tout message (événement, commande ou résultat) créé en réaction à un autre message M, reprend tel quel l’identifiant de conversation de M M.

Tous les messages consécutifs à un événement initial donné partagent le même identifiant de conversation, ce qui n’est le cas d’aucun autre événement. De cette façon, nous pouvons facilement retracer et déboguer le pipeline réel de chaque appel entrant, par exemple.

Enfin, les schémas de messages doivent être compatibles en aval :

  • une nouvelle version d’un schéma de messages pour une application peut ajouter des champs, mais ne doit pas supprimer ou redéfinir les champs existants ;
  • l’implémentation d’un décodeur de messages doit ignorer les champs inconnus sans se planter.

La documentation détaillée des messages réels doit être tenue à jour dans un endroit facilement accessible par les développeurs.

Dans le prochain article de cette série, nous verrons comment nous avons mis en œuvre ces principes et comportements dans l’architecture réelle.

Partagez c'est sympa !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *