/ design patterns

Integraciones - retries resilience4j | nopaldev

Veamos por qué es importante realizar reintentos a un servicio externo y cómo implementarlo en Java utilizando resilience4j

En esta serie de publicaciones sobre integraciones, veremos distintos patrones de diseño y mejores prácticas para la conexión con sistemas externos, en esta ocasión nos enfocaremos únicamente a los reintentos

introducción

Para las integraciones, debemos entender que los servicios que vamos a consumir podrían tener problemas y por por lo tanto verse reflejados en los servicios de downstream (todo aquel que depende del servicio)

nopaldev-integraciones

Hay que tener en mente que los sistemas terceros, igual que nuestros sistemas, pasan por distintos procesos que podrían dejarlos inactivos por algún momento: despliegues de nuevas versiones, bugs introducidos en nuevas versiones, rollbacks, tiempos de procesamiento muy altos, etc. Sabiendo esto, debemos prepararnos para evitar tener una mala experiencia de usuario, es decir, fallar con clase

reintentos

Debido a que los sistemas terceros pueden tener intermitencia en algún punto, es importante asegurarnos de reintentar las transacciones a realizar dentro de una ventana considerable. Para ejemplificar esto, imaginemos el siguiente escenario:

Tenemos que descargar todas las publicaciones de un blog externo a nuestro sistema local

Las variables a considerar serían entonces: latencia y disponibilidad del servicio. Inicialmente tendríamos una sola llamada al servicio de la siguiente forma:

Screenshot-from-2021-04-03-12-56-47

Entonces, desde una capa superior, podríamos sólo ejecutar los llamados para aplicar la lógica que necesitamos

Screenshot-from-2021-04-03-12-59-11

Ejecutando este código validaremos que únicamente estamos realizando un llamado del servicio para el escenario en que el servicio no está disponible (pueden agregar una URL de un servicio que no exista)

Screenshot-from-2021-04-03-13-03-47

configurando los reintentos

Para este ejemplo utilizaremos una aplicación de consola en Java 11, Resilience4J para el manejo de la integración y gradle para el manejo de dependencias. La razón por la cual no usaremos spring en este ejemplo es para delimitar la cantidad de magia y por lo tanto dependencia que tendríamos a un framework específico para el uso de resilience4j

La configuración de reintentos que utilizaremos será básica:

  • 3 intentos
  • Un intervalo de 1 segundo entre cada reintento
  • Aplicar los reintentos únicamente para las excepciones de conexión IOException e InterruptedException en este caso
  • Finalmente, le indicamos que falle todo el mecanismo cuando alcancemos la cantidad máxima de intentos

Screenshot-from-2021-04-03-13-07-30

Finalmente, sólo basta con hacer un wrap de nuestro método que ejecuta la conexión de la siguiente forma:

Screenshot-from-2021-04-03-13-09-30

Como puedes observar, la lógica principal del método pullPosts se mantiene idéntico y sólo decoramos (equivalente a utilizar una anotación) nuestro método con la configuración que creamos previamente

Ahora obtenemos los llamados con los intervalos que definimos para consumir el servicio:

Screenshot-from-2021-04-03-13-13-56

conclusiones

Es importante tener el control de los escenarios de fallo para todas las integraciones, esto brindará una mejor experiencia de usuario y entendimiento de nuestro sistema para seguir madurando

Resilience4j es una librería para Java muy sencilla de utilizar que provee mecanismos necesarios para el manejo de los reintentos

En los siguientes posts hablaremos de circuit breaker, time outs, read timeouts y mejores prácticas para desarrollo y ambientes de producción con implementaciones en el mismo proyecto de Java

Puedes encontrar el código de este ejemplo en la siguiente liga: https://github.com/carlosJoseloMtz/nopaldev-integrationsposts