mvn clean install tomee:runMicroProfile Fault Tolerance - Retry Policy
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 specification para mais detalhes.
Exemplos
Execute o aplicativo
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).
@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
GET http://localhost:8080/mp-faulttolerance-retry/weather/day/statusServer log
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
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.
@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
GET http://localhost:8080/mp-faulttolerance-retry/weather/week/statusServer log
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
WeatherGateway Service is Busy. Retry laterExemplo 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.
@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
GET http://localhost:8080/mp-faulttolerance-retry/weather/weekend/statusServer log
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) millisExemplo 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.
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.
@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
GET http://localhost:8080/mp-faulttolerance-retry/weather/month/statusServer log
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) millisExample 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.
@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
GET http://localhost:8080/mp-faulttolerance-retry/weather/year/statuskServer log
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) millisExecute os testes
Você também pode experimentar usando WeatherServiceTest.java disponível no projeto.
mvn clean test[INFO] Results:
[INFO]
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0