blob: 4dab10eecae1674b08d3c63d70e514c521ae2e18 [file] [log] [blame]
= MicroProfile Fault Tolerance - Retry Policy
:index-group: MicroProfile
:jbake-type: page
:jbake-status: published
Este é um exemplo de como usar
Microprofile @Retry em TomEE.
== Retry Feature
Microprofile Fault Tolerance tem um recurso chamado Retry que pode ser usado
para recuperar uma operação de falha, chamando a mesma operação novamente
até atingir seus critérios de parada.
A Retry policy permite configurar :
* *maxRetries*: o máximo de tentativas
* *delay*: atrasos entre cada tentativa
* *delayUnit*: a unidade de atraso
* *maxDuration*: duração máxima para executar a nova tentativa
* *durationUnit*: unidade de duração
* *jitter:* a variação aleatória dos atrasos de uma nova tentativa
* *jitterDelayUnit:* a unidade de instabilidade
* *retryOn:* especifique as falhas para tentar novamente
* *abortOn:* especifique as falhas para abortar
Para usar esse recurso, você pode anotar uma classe e/ou um método com a anotação @Retry. Verifique em
http://download.eclipse.org/microprofile/microprofile-fault-tolerance-1.1/microprofile-fault-tolerance-spec.html[specification]
para mais detalhes.
== Exemplos
=== Execute o aplicativo
[source,java]
----
mvn clean install tomee:run
----
=== Exemplo 1
O método statusOfDay falhará 3 (três) vezes, a cada vez, lançando uma
`WeatherGatewayTimeoutException` e como a anotação @Retry está
configurada para `retryOn` em caso de falha, a biblioteca FailSafe pegará
o valor `maxRetry` e tentará a mesma operação até atingir o número máximo de tentativas, que é 3 (valor padrão).
[source,java]
----
@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!";
}
...
}
----
Chamada de status do dia
[source,java]
----
GET http://localhost:8080/mp-faulttolerance-retry/weather/day/status
----
Server log
[source,java]
----
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)
----
Response
[source,java]
----
Today is a sunny day!
----
=== Exemplo 2
O método weekStatus falhará duas vezes, a cada vez, lançando uma
`WeatherGatewayTimeoutException` porque `retryOn` está configurado e
em vez de retornar uma resposta ao chamador, a lógica afirma que na terceira tentativa uma
`WeatherGatewayBusyServiceException` será lançada. Como a anotação `@Retry` está configurada para
`abortOn` no caso de `WeatherGatewayTimeoutException` ocorrer, a tentativa restante não será
executada e o chamador deve lidar com a exceção.
[source,java]
----
@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();
}
----
Chamada de status da semana
[source,java]
----
GET http://localhost:8080/mp-faulttolerance-retry/weather/week/status
----
Server log
[source,java]
----
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)
----
Response
[source,java]
----
WeatherGateway Service is Busy. Retry later
----
=== Exemplo 3
A anotação `@Retry` permite configurar um atraso para cada nova tentativa
ser executada, dando a chance ao serviço solicitado para se recuperar e
responder a solicitação corretamente. Para cada nova tentativa, seguindo o atraso
configurado, é necessário definir `jitter` como zero (0). Caso contrário, o atraso de
cada nova tentativa será aleatório.
Analisando o log de mensagens, é possível ver que todas as tentativas levaram
praticamente o mesmo tempo para executar.
[source,java]
----
@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.";
}
----
Chamada de status de fim de semana
[source,java]
----
GET http://localhost:8080/mp-faulttolerance-retry/weather/weekend/status
----
Server log
[source,java]
----
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
----
=== Exemplo 4
Basicamente com o mesmo comportamento do `Exemplo 3`, este exemplo defini
o `delay` e o `jitter` com 500 milissegundos para aleatoriamente um novo atraso a cada nova tentativa
após a primeira falha.
https://github.com/jhalterman/failsafe/blob/master/src/main/java/net/jodah/failsafe/AbstractExecution.java[AbstractExecution#randomDelay(delay,jitter,random)]
pode dar uma ideia de como o novo atraso é calculado.
Analisando o log de mensagens, é possível ver quanto tempo cada tentativa teve
que esperar até a sua execução.
[source,java]
----
@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.";
}
----
Chamada de status do mês
[source,java]
----
GET http://localhost:8080/mp-faulttolerance-retry/weather/month/status
----
Server log
[source,java]
----
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
----
=== Example 5
Se uma condição para uma operação re-executada não estiver definida como nos
exemplos anteriores usando o parâmetro `retryOn`, a operação é
executada novamente para qualquer exceção lançada.
[source,java]
----
@Retry(maxDuration = 1000)
public String statusOfYear(){
if (counterStatusOfWeekend.addAndGet(1) <= 5) {
logTimeoutMessage(statusOfYearInstant);
statusOfYearInstant = Instant.now();
throw new RuntimeException();
}
return "WeatherGateway Service Error";
}
----
Chamada de status do ano
[source,java]
----
GET http://localhost:8080/mp-faulttolerance-retry/weather/year/statusk
----
Server log
[source,java]
----
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
----
=== Execute os testes
Você também pode experimentar usando
link:src/test/java/org/superbiz/rest/WeatherServiceTest.java[WeatherServiceTest.java]
disponível no projeto.
[source,java]
----
mvn clean test
----
[source,java]
----
[INFO] Results:
[INFO]
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
----