Comme indiqué dans le billet "Vers une infrastructure en micro services", Gadz.org s'oriente vers une architecture en micro service. J'expose ici les problèmes que cela pose pour la gestion des erreurs.
Lors du traitement d'un message, un service consommateur peut rencontrer des erreurs. Il s'agit d’événement empêchant le traitement correct du message.
On sépare trois 3 natures d'erreurs :
Les erreurs "métier"
Il s'agit d'erreurs liées à la logique métier du service. Exemples : inscription d'un utilisateur à une liste de diffusion dont il fait déjà partit, attribution d'une adresse mail déjà attribuée...
Les erreurs "techniques"
Ce sont des erreurs qui apparaissent lors de l'execution du service. Exemples : Reception d'un message ne respectant pas le format défini les spécifications, bug du à un caractère invalid ou tout autre bug provoquant l’interruption involontaire du service.
Les erreurs de disponibilité
Elles interviennent lorsqu'une ressource extérieure nécessaire au traitement du message n'est pas disponible. Exemple : base de donnée indisponible, accès aux API Google suite à un dépassement de quota, etc. Ces erreurs sont parfois considérées comme un cas particulier des erreurs techniques.
Il est également possible de classer les erreurs en 2 types :
Les erreurs remédiables
Une erreur est dite remédiable lorsque le meme message peut être traiter en reessayant plus tard ou en étant traiter d'une autre manière (eventuellement en l'envoyant à un autre service)
Les erreurs irrémédiables
Les erreurs irrémédiables sont dues à la nature même du message ou à l'implémentation technique du service. Ce message ne pourra jamais être traiter
Les erreurs de disponibilité sont généralement remédiable. A l'inverse, les erreurs technique sont souvent irrémédiables.
Dans une première approche, nous avons choisi une solution simple de la gestion des erreurs. Nous ne considérons que 2 types d'erreurs : les erreurs remédiables (Softfail) et les erreurs irrémédiables (Hardfail). Il s'agit d'une généralisation de l'approche utilisée par les X lors du développement de GappsD [Github] notre ancien système de synchronisation GoogleApps. Les règles sont les suivantes :
La zone tampon est indépendante du service qui a provoqué l'erreur. En pratique, nous utilisons une queue RabbitMQ ayant une date d'expiration [documentation technique]
Voici un exemple d'utilisation :
Etapes :
Cette approche à plusieurs avantages :
Mais cette approche ne fonctionne que dans un cas très précis : le message ne peut exister qu'à un seul endroit à la fois. Il ne peut pas être dupliquer pour être envoyé à plusieurs services simultanément.
Prenons un autre exemple pour mieux comprendre le problème :
Dans cet exemple nous changeons de fonctionnement. Plutôt que d'appeler explicitement les services, nous utilisons un système de "notification". A chaque nouvel utilisateur enregistré dans l'application GrAM, un message avec la clé de routage "notify.gram.user.created" est envoyé. Les services abonnés à cette notification recevront le message. Dans cet exemple, 2 services sont abonnés à "notify.gram.user.created" :
Reprenons le fonctionnement précédent :
En suivant ce protocole, un nouveau mail est envoyé à chaque Softfail généré par GoogleApps Service. De plus, si des erreurs apparaissent simultanément dans plusieurs services, l'historique des erreurs présent dans le contenu du messages ne sera pas cohérent entre les différentes instances de ce message.
Plus généralement, ceci pose la question du traitement des Softfails. Doit-on ré-effectuer toutes les actions ou uniquement celles en erreur ?
Une autre approche est donc necessaire. Les différentes solutions envisagées feront l'objet d'un autre billet de blog.
N'hésitez pas à participer et proposer des solutions via les commentaires ou sur le Slack de Gadz.org