Modèle de nouvelle tentative: exemples et recommandations


Aujourd’hui, je voudrais parler de Modèle de nouvelle tentative. Dans les applications distribuées, où des communications constantes sont établies entre les services et / ou les ressources externes, des défaillances temporaires ou transitoires (défaillances transitoires) peuvent se produire lors de l’interaction avec ces environnements. Ces défaillances peuvent être causées par différentes raisons, parmi les plus courantes sont les pertes momentanées de connexion au réseau, les services temporairement indisponibles, les temps de réponse dépassés, etc.

Normalement, ces erreurs sont résolues automatiquement et dans un court laps de temps de sorte que si le service ou la ressource est invoqué, il répond immédiatement correctement. Un exemple classique d’une erreur transitoire est l’échec de la connexion à la base de données en raison d’un pic de connexions simultanées qui dépassent le nombre maximal autorisé par configuration.

Cependant, bien qu’il s’agisse d’erreurs rares, ces échecs doivent être gérés correctement par l’application pour minimiser l’impact sur celle-ci. Une solution possible à ce problème est l’application de la Modèle de nouvelle tentative.

Modèle de nouvelle tentative

Le modèle de nouvelle tentative est connu sous le nom de modèle de stabilité et comme son nom l’indique, il s’agit de réessayer une opération qui a échoué. En fait, c’est une définition très simpliste et il faut ajouter qu’en fonction du type d’erreur détecté et / ou du nombre de tentatives, différentes actions peuvent être effectuées:

  • Réessayez: Si l’erreur indique qu’il s’agit d’une défaillance temporaire ou d’une défaillance atypique, l’application peut réessayer immédiatement la même opération car la même erreur ne se reproduira probablement pas.
  • Réessayez après un temps d’attente: Si l’erreur s’est produite en raison d’un problème de connexion réseau ou d’un pic de demandes au service, il peut être prudent de prévoir un certain temps avant de tenter d’effectuer à nouveau l’opération.
  • Annuler: Si l’erreur indique que nous ne sommes pas confrontés à une défaillance temporaire, l’opération doit être annulée et l’erreur signalée ou gérée correctement.

Ces actions peuvent être combinées pour créer une politique de nouvelle tentative adaptée aux besoins de notre application.

Ce serait un exemple d’une implémentation simple dans Kotlin où seul le nombre de tentatives infructueuses est pris en compte et il y a un temps d’attente entre chaque nouvelle tentative:

Bien sûr, les implémentations peuvent être beaucoup plus sophistiquées. On peut avoir, par exemple, une implémentation qui commence par une politique de relances consécutives car il est normal que le service se rétablisse rapidement. Si après un certain nombre de tentatives consécutives l’erreur persiste, nous pouvons passer à l’inclusion d’une période d’attente prudentielle entre les tentatives et enfin si le service ne se rétablit toujours pas, nous pouvons procéder à l’annulation de l’opération.

La complexité de l’implémentation doit répondre aux besoins réels de notre application et aux exigences métier.

Il existe des bibliothèques qui implémentent le modèle Retry de manière simple, comme Spring Retry.

Comme nous pouvons le voir, l’implémentation à travers cette bibliothèque est très simple. Dans l’exemple, nous pouvons voir que la première chose à faire est de configurer l’application avec l’annotation @EnableRetry.

Ensuite, nous ajoutons l’annotation @Retryable avec laquelle la méthode qui va être «tentée à nouveau» est indiquée en cas d’erreur. L’annotation @Recover indique où l’exécution se poursuivra au cas où le nombre maximal de tentatives serait dépassé (maxAttempts = 2) lorsque l’erreur est du type RemoteAccessException.

Vous pouvez trouver l’exemple complet sur GitHub (le lien se trouve à la fin de l’article).

Nous pouvons vérifier le flux du motif dans la sortie de la console. L’exécution a réussi jusqu’à ce qu’elle trouve une erreur transitoire, à ce moment-là, elle a recommencé l’opération deux fois comme spécifié dans la configuration et lorsque la même erreur persiste, elle est passée par la méthode de récupération.

Ce modèle fonctionne très bien lorsque les erreurs sont transitoires, sporadiques et sont résolues dans un appel ultérieur, mais un une série de considérations doivent être prises en compte lors de son application:

  • Le type d’erreur: ce doit être une erreur qui nous dit qu’elle peut être récupérée rapidement.
  • La criticité de l’erreur: une nouvelle tentative peut avoir une influence négative sur les performances de l’application. Dans certaines situations, il est plus optimal de gérer l’erreur et de demander à l’utilisateur de décider s’il souhaite réessayer l’opération.
  • La politique des nouvelles tentatives: une politique de relance continue de l’opération, notamment sans temps d’attente, pourrait aggraver le statut du service à distance.
  • Effets collatéraux: Si l’opération n’est pas idempotente, il n’est pas possible de garantir qu’une nouvelle tentative conduira au résultat attendu.

Il n’est pas conseillé d’utiliser ce modèle en cas de:

  • Gestion des erreurs non transitoires qui ne sont pas liées à des défaillances de connexion ou de service (telles que des erreurs de logique métier).
  • Les erreurs durables. Le temps d’attente et les ressources nécessaires sont trop élevés. Pour ces cas, il existe des solutions telles que l’application du modèle de disjoncteur dont nous discuterons dans un autre article.

Je tiens à souligner qu’il est fortement recommandé de conserver un enregistrement des opérations ayant échoué car il s’agit d’informations très utiles pour aider à dimensionner correctement l’infrastructure d’un projet et trouver les erreurs récurrentes et les erreurs réduites au silence par la gestion des erreurs de l’application.

Vous pouvez trouver les exemples complets discutés dans cet article dans notre GitHub.

Close Menu