mvn clean install tomee:run
MicroProfile Fault Tolerance - Retry Policy
Este es un ejemplo de cómo usar Microprofile @Retry en TomEE.
Retry Feature
Microprofile Fault Tolerance tiene una función llamada Reintentar que se puede utilizar para recuperase de una operación del error, invocando la misma operación de nuevo hasta que se alcancen los criterios de detención.
La directiva de reintento permite configurar:
-
maxRetries: los reintentos máximos
-
delay: retrasos entre cada reintento
-
delayUnit: la unidad de retardo
-
maxDuration: duración máxima para realizar el reintento.
-
durationUnit: unidad de duración
-
jitter: la variación aleatoria de retrasos de reintento
-
jitterDelayUnit: la unidad de fluctuación
-
retryOn: especifica reintentar en caso de errores
-
abortOn: especifica anular en caso de errores
Para utilizar esta función puede anotar una clase y/o método con la anotación @Retry
. Compruebe la
especificación
para más detalles.
Ejemplos
Ejecutar la aplicación
Ejemplo 1
El método statusOfDay producirá un error tres veces, cada vez,
lanzando una 'WeatherGatewayTimeoutException' y como la anotación @Retry
está configurada para retryOn
en caso de error, la libreria FailSafe tomará
el valor maxRetry
y volverá a intentar la misma operación hasta que alcance
el número máximo de intentos, que es 3 (valor predeterminado).
@RequestScoped
public class WeatherGateway{
...
@Retry(maxRetry=3, retryOn = WeatherGatewayTimeoutException.class)
public String statusOfDay(){
if(counterStatusOfDay.addAndGet(1) <= DEFAULT_MAX_RETRY){
LOGGER.warning(String.format(FORECAST_TIMEOUT_MESSAGE, DEFAULT_MAX_RETRY, counterStatusOfDay.get()));
throw new WeatherGatewayTimeoutException();
}
return "Today is a sunny day!";
}
...
}
Llamada de estado del día
GET http://localhost:8080/mp-faulttolerance-retry/weather/day/status
Registro del servidor
WARNING - Timeout when accessing AccuWeather Forecast Service. Max of Attempts: (3), Attempts: (1)
WARNING - Timeout when accessing AccuWeather Forecast Service. Max of Attempts: (3), Attempts: (2)
WARNING - Timeout when accessing AccuWeather Forecast Service. Max of Attempts: (3), Attempts: (3)
Respuesta
Today is a sunny day! (¡Hoy es un día soleado!)
Ejemplo 2
El método weekStatus fallará dos veces, cada vez, lanzando una excepción
WeatherGatewayTimeoutException
porque retryOn
está configurado y
en lugar de devolver una respuesta al autor de la llamada, la lógica indica que en
el tercer intento, una excepción WeatherGatewayBusyServiceException
será
lanzada. Como la anotación @Retry
está configurada para abortOn
en caso que
WeatherGatewayTimeoutException
ocurra, el intento restante no será
ejecutado y el autor de la llamada tendra que controlar la excepción.
@Retry(maxRetries = 3, retryOn = WeatherGatewayTimeoutException.class, abortOn = WeatherGatewayBusyServiceException.class)
public String statusOfWeek(){
if(counterStatusOfWeek.addAndGet(1) <= DEFAULT_MAX_RETRY){
LOGGER.warning(String.format(FORECAST_TIMEOUT_MESSAGE_ATTEMPTS, DEFAULT_MAX_RETRY, counterStatusOfWeek.get()));
throw new WeatherGatewayTimeoutException();
}
LOGGER.log(Level.SEVERE, String.format(FORECAST_BUSY_MESSAGE, counterStatusOfWeek.get()));
throw new WeatherGatewayBusyServiceException();
}
Llamada de estado de la semana
GET http://localhost:8080/mp-faulttolerance-retry/weather/week/status
Registro del servidor
WARNING - Timeout when accessing AccuWeather Forecast Service. Max of Attempts: (3), Attempts: (1)
WARNING - Timeout when accessing AccuWeather Forecast Service. Max of Attempts: (3), Attempts: (2)
WARNING - Timeout when accessing AccuWeather Forecast Service. Max of Attempts: (3), Attempts: (3)
SEVERE - Error AccuWeather Forecast Service is busy. Number of Attempts: (4)
Respuesta
WeatherGateway Service is Busy. Retry later
Ejemplo 3
La anotación @Retry
permite configurar un retraso para ejecutar cada nuevo intento
dando la oportunidad al servicio solicitado para recuperarse y contestador de la
solicitud correctamente. Para cada nuevo reintento siga el retraso
configurar, es necesario establecer jitter
a cero (0). De lo contrario, el retraso de
cada nuevo intento será aleatorio.
Analizando los mensajes registrados, es posible ver que todos los intentos toman más o menos el mismo tiempo para ejecutar.
@Retry(retryOn = WeatherGatewayTimeoutException.class, maxRetries = 5, delay = 500, jitter = 0)
public String statusOfWeekend() {
if (counterStatusOfWeekend.addAndGet(1) <= 5) {
logTimeoutMessage(statusOfWeekendInstant);
statusOfWeekendInstant = Instant.now();
throw new WeatherGatewayTimeoutException();
}
return "The Forecast for the Weekend is Scattered Showers.";
}
Llamada de estado de la semana
GET http://localhost:8080/mp-faulttolerance-retry/weather/weekend/status
Registro del servidor
WARNING - Timeout when accessing AccuWeather Forecast Service.
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (501) millis
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (501) millis
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (501) millis
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (500) millis
Ejemplo 4
Básicamente con el mismo comportamiento del Ejemplo 3
, este ejemplo establece
el delay
y el jitter
con 500 milisegundos para crear aleatoriamente un nuevo retardo
para cada nuevo intento después del primer error.
AbstractExecution-randomDelay(delay,jitter,random) puede dar una idea de cómo se calcula el nuevo retraso.
Mediante el análisis de los mensajes registrados, es posible ver cuanto cada intento tiene que esperar antes de ejecutarse.
@Retry(retryOn = WeatherGatewayTimeoutException.class, delay = 500, jitter = 500)
public String statusOfMonth() {
if (counterStatusOfWeekend.addAndGet(1) <= DEFAULT_MAX_RETRY) {
logTimeoutMessage(statusOfMonthInstant);
statusOfMonthInstant = Instant.now();
throw new WeatherGatewayTimeoutException();
}
return "The Forecast for the Weekend is Scattered Showers.";
}
Llamada de estado del mes
GET http://localhost:8080/mp-faulttolerance-retry/weather/month/status
Registro del servidor
WARNING - Timeout when accessing AccuWeather Forecast Service.
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (417) millis
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (90) millis
Ejemplo 5
Si no se establece una condición para que una operación que se vuelva a ejecutar
como en los ejemplos anteriores mediante el parámetro retryOn
, la operación
se ejecuta de nuevo para cualquier excepción que se produce.
@Retry(maxDuration = 1000)
public String statusOfYear(){
if (counterStatusOfWeekend.addAndGet(1) <= 5) {
logTimeoutMessage(statusOfYearInstant);
statusOfYearInstant = Instant.now();
throw new RuntimeException();
}
return "WeatherGateway Service Error";
}
Llamada de estado del año
GET http://localhost:8080/mp-faulttolerance-retry/weather/year/statusk
Registro del servidor
WARNING - Timeout when accessing AccuWeather Forecast Service.
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (666) millis
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (266) millis
WARNING - Timeout when accessing AccuWeather Forecast Service. Delay before this attempt: (66) millis
Ejecutar las pruebas
También puede probarlo utilizando el enlace:src/test/java/org/superbiz/rest/WeatherServiceTest.java[WeatherServiceTest.java] disponible en el proyecto.
mvn clean test
[INFO] Results:
[INFO]
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0