RES1 - Configuración de Resiliencia y Reintentos (HTTP)
|
Para Comenzar
El paso del tutorial utiliza el Si en algún momento desea ver la solución a este paso, esta se puede encontrar en el |
En CON3 - Escribiendo su propio conector (HTTP), conectamos nuestra aplicación con sistemas de prueba de fraude externos. Esto nos proporcionó una conexión sincrónica a un sistema externo que es inherentemente menos estable que utilizar Kafka or JMS. Y nuestro paisaje en este punto de los tutoriales se ve así;
En este tutorial, vamos a analizar cómo podemos controlar la resiliencia y la configuración de reintentos en un esfuerzo por permitir la HTTP llamada para tener éxito. Haremos esto simulando fallos del fraud-sim de tal manera que HTTP las llamadas a ese servicio fallarán.
Iniciando la Aplicación
Si el entorno no está en funcionamiento, necesitamos iniciar nuestro docker entorno. Inicie la aplicación como se indicó anteriormente (instructions están disponibles en Revisando la solicitud inicial si necesita un repaso)
Esto debería iniciar todas las aplicaciones y simuladores. Puede verificar si los contenedores están iniciados y saludables utilizando el comando:
docker ps -a
Valide el procesamiento BAU
Primero, verifique que todo esté funcionando en BAU, con todos los puntos finales del simulador activos y en funcionamiento, y envíe un pago:
curl -X POST localhost:8080/submit -H 'Content-Type: application/json' -d '{"value": "25"}' | jq
Verificando el pago en el Aplicación para Desarrolladores podemos ver los mensajes que se envían y detectar los mensajes OlafRequest y OlafResponse para el fraude-sim (search by unit of work id, haga clic en ver, haga clic en el flujo del tutorial de ipf, haga clic en mensajes) entonces vemos:
Escenario de Prueba de Fallo
Suponiendo que todo esté bien con el procesamiento de BAU, probemos el escenario en el que el fraud-sim está inactivo y las respuestas de Olaf no están llegando. La forma más sencilla de hacerlo es detener el contenedor de fraud-sim:
docker stop fraud-sim
Una vez que el contenedor esté inactivo, podemos enviar otra solicitud de pago:
curl -X POST localhost:8080/submit -H 'Content-Type: application/json' -d '{"value": "24"}' | jq
Al verificar el pago en la Aplicación para Desarrolladores nuevamente, usted debería ver el OlafRequest siendo enviado, pero no el OlafResponse regresando, y el estado de la transacción en sí se muestra como RECHAZADO (esto se debe a que la solicitud ha excedido el tiempo de espera y ha sido movida a un estado de rechazado).state):
Finalmente, desde la Aplicación del Desarrollador podemos ver el system event que ha sido generado para esta falla:
También vale la pena revisar los registros del contenedor para ver la excepción y los errores específicos (esto se volverá importante a medida que configuremos el servicio para reintentar el HTTP llamada). Notará que no hay más errores, el procesamiento se detiene efectivamente con nuestra configuración actual:
07-05-2025 17:33:51. 180 [ipf-flow-akka.actor.default-dispatcher-58] ERROR c.i.ipf.core.connector. SendConnector.lambda$send$12 - Sending via Fraud completed exceptionally for ProcessingContext(associationId=AssociationId(value=IpftutorialflowV2|b1a09a4d-5bb8-4d32-b262-c5a8c100f03b), checkpoint=Checkpoint(value=PROCESS_FLOW_EVENT|IpftutorialflowV2|b1a09a4d-5bb8-4d32-b262-c5a8c100f03b|6), unitOfWorkId=UnitOfWorkId(value=b863295e-fa2f-44d0-9588-2fa62f1301d3), clientRequestId=ClientRequestId(value=90838f2e-d79c-4edc-b122-e5d3e6e1fadc), processingEntity=ProcessingEntity(value=UNKNOWN))
java.util.concurrent. CompletionException: java.lang. IllegalStateException: No closed routees for connector: Fraud. Calls are failing fast
..
.
.
Caused by: java.lang. IllegalStateException: No closed routees for connector: Fraud. Calls are failing fast
at com.iconsolutions.ipf.core.connector.resiliency. ResiliencyPassthrough.sendResiliently(ResiliencyPassthrough.java:125)
.. 40 common frames omitted
Caused by: akka.stream. StreamTcpException: Tcp command [Connect(localhost/<unresolved>:8089, None,List(), Some(10 seconds), true)] failed because of java.net. ConnectException: Connection refused
Caused by: java.net. ConnectException: Connection refused
Configure la configuración de tiempo de espera y resiliencia
En la situación actual de la aplicación tutorial, no está configurada proactivamente para reintentos y no ha establecido los ajustes de resiliencia para protegerse contra errores intermitentes en el HTTP conexión sincrónica.
Consideraciones sobre el tiempo de espera de la acción
Como habrá notado, la Solicitud de Fraude ha expirado y el flujo ha progresado a un estado terminal.state de Rechazado. En DSL 7 - Manejo Timeouts hemos configurado el Tiempo de Espera de Acción para que sea de 2 segundos.
Para los propósitos de este tutorial, queremos dar a esa acción un poco más de tiempo para completarse normalmente (suficiente tiempo para simular una falla intermitente y permitir que la configuración de resiliencia reintente las solicitudes). Para hacer esto, debemos aumentar la configuración en nuestros recursos/application.conf archivo:
flow. Ipftutorialflow V2. CheckingFraud. CheckFraud.timeout-duration=60s
Configure la Configuración de Resiliencia para Reintentar
Es posible definir configuraciones de resiliencia para reintentar el HTTP llamada dentro de un período definido y a intervalos configurables. La configuración predeterminada se muestra a continuación, incluyendo tanto la configuración del conector como la configuración de resiliencia.
Ahora actualizaremos los intentos máximos de resiliencia de los Conectores a 6, lo cual está destinado a proporcionar suficientes reintentos de la HTTP llamada para permitir que el servicio de simulación de fraude se recupere (intentos de 6, junto con el multiplicador de retroceso de 2 segundos, deberían dar 5 intentos antes del tiempo de espera de la llamada de 30 segundos)
Añadirá nuestra configuración en el archivo de configuración de nuestra aplicación (resources/application.conf):
fraud {
transport = http
http {
client {
host = "fraud-sim"
port = "8080"
endpoint-url = "/v1"
}
}
connector {
resiliency-settings {
max-attempts = 6
}
}
}
Escenario de Fallo Prueba 2
Ahora podemos aplicar esta configuración reconstruyendo el contenedor ipf-tutorial-app (mvn clean install -rf:ipf-tutorial-app) y iniciándolo, luego debe seguir los siguientes pasos de prueba:
DADO que el fraud-sim está detenido && la aplicación ipf-tutorial-app tiene configuraciones de resiliencia para reintentar HTTP llamadas
CUANDO se inicia un pago && el fraude-sim se recupera dentro del tiempo de espera del conector de 30 segundos
ENTONCES el pago completará el procesamiento con retraso y reintentos evidentes en los registros.
docker stop fraud-sim
curl -X POST localhost:8080/submit -H 'Content-Type: application/json' -d '{"value": "23"}' | jq
Espere 5 segundos (esto permitirá que el Conector intente nuevamente).
docker start fraud-sim
Si usted está observando los registros de la ipf-tutorial-app (cambie los recursos/logback.xml para que ipf-tutorial-app tenga <logger name="com.iconsolutions.ipf" level="DEBUG"/> ) y usted debe ver entradas de reintento como (nota-esto es el decision para reintentar, el reintento real ocurre una vez que ha expirado el período de retroceso):
07-05-2025 17:57:51. 784 [ipf-flow-akka.actor.default-dispatcher-35] WARN c.i.i.c.c.t. HttpConnectorTransport.lambda$processReceivedResponse$da95b82c$1 - Failure reply for association ID [UnitOfWorkId(value=07650576-8664-422b-a7d1-98635c767865)] with exception [OutgoingConnectionBlueprint. UnexpectedConnectionClosureException: The http server closed the connection unexpectedly before delivering responses for 1 outstanding requests] and message [TransportMessage(, httpStatusCode -> 500 Internal Server Error)]
07-05-2025 17:57:51. 790 [ipf-flow-akka.actor.default-dispatcher-35] DEBUG c.i.i.c.c.r. ResiliencySettings.lambda$resolveRetryOnSendResultsWhen$6 - retryOnResult decided to retry this attempt since it was a failure: DeliveryReport(outcome=FAILURE, deliveryException=akka.http.impl.engine.client. OutgoingConnectionBlueprint$UnexpectedConnectionClosureException: The http server closed the connection unexpectedly before delivering responses for 1 outstanding requests)
Una vez que haya transcurrido el período de espera, se llevará a cabo el reintento real:
07-05-2025 17:57:54. 803 [pool-5-thread-1] DEBUG c.i.i.c.c.r. ResiliencyPassthrough.sendViaTransport - Calling 07650576-8664-422b-a7d1-98635c767865: using OlafRequestReplyHttpConnectorTransport
Al verificar el pago en la Aplicación para Desarrolladores nuevamente, usted debería ver el OlafRequest siendo enviado, pero la respuesta de éxito en la pestaña de Mensajes aparece después de un retraso (aproximadamente 15 segundos).
-
Puede configurar los reintentos de manera flexible considerando el multiplicador de retroceso y la duración inicial de espera para el reintento. Por ejemplo
| duración Inicial De Espera Para Reintentos | backoffMultiplier | Primeros 5 intervalos de intento |
|---|---|---|
1 |
2 |
1, 2, 4, 8, 16 |
5 |
2 |
5, 10, 20, 40, 80 |
1 |
5 |
1, 5, 25, 125, 625 |
-
Este reintento ocurrió dentro del tiempo de espera del conector de 30 segundos. Por lo tanto, también debe considerar el tiempo de espera de la llamada en conjunto con la configuración de resiliencia.
-
Según está redactado el tutorial, si el reintento no tiene éxito dentro de esos 60 segundos, esto regresará al flujo y la verificación de fraude no se habrá completado.
-
Este es un buen ejemplo de algo que es transitorio a corto plazo y se resuelve rápidamente. Cuando ese no es el caso, tenemos varias opciones para configurar puntos finales de transporte adicionales, para "reintentar" desde el flujo definiendo la lógica empresarial apropiada en el DSL de IPF.
-
También tenemos las opciones de reaccionar de manera diferente a las respuestas comerciales reales (utilizando retryOnResultWhen), para reintentar en ciertos códigos de error comercial devueltos por la aplicación llamada. Sin embargo, esto debe equilibrarse con la cantidad de lógica que desea en el nivel del conector frente a la lógica del flujo.
-
El componente de resiliencia se implementa con resilience4j. Consulte documentación sobre Resilience4j marco para obtener más información sobre estas configuraciones y behaviours.