

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Tentar novamente atividades com falha
<a name="features-retry"></a>

As atividades falham às vezes por motivos efêmeros, como uma perda temporária de conectividade. Em outro momento, a atividade pode funcionar, assim a forma apropriada de lidar com falhas de atividade geralmente é repetir a atividade, talvez algumas vezes. 

Existe uma variedade de estratégias para repetir atividades. A melhor depende dos detalhes do fluxo de trabalho. As estratégias são divididas em três categorias básicas: 
+ A retry-until-success estratégia simplesmente continua repetindo a atividade até que ela seja concluída.
+ A estratégia de repetição exponencial aumenta o intervalo de tempo entre as tentativas exponencialmente até que a atividade seja concluída ou o processo alcançar um ponto de parada especificado, como um número máximo de tentativas.
+ A estratégia de repetição personalizada decide se ou como repetir a atividade após cada tentativa falha.

As seções a seguir descrevem como implementar essas estratégias. Todos os operadores de fluxo de trabalho de exemplo utilizam uma única atividade, `unreliableActivity`, que realiza de forma aleatória um dos seguintes: 
+ Conclui imediatamente
+ Falha intencionalmente ao exceder o valor do tempo limite
+ Falha intencionalmente lançando uma `IllegalStateException` 

## Retry-Until-Success Estratégia
<a name="features-retry-success"></a>

A estratégia mais simples de repetição é continuar repetindo a atividade até que eventualmente seja concluída. O padrão básico é:

1. Implementar uma classe aninhada `TryCatch` ou `TryCatchFinally` no método do ponto de entrada do fluxo de trabalho.

1. Executar a atividade em `doTry`

1. Se a atividade falhar, a estrutura chama `doCatch`, que executa o método do ponto de entrada novamente.

1. Repetir as Etapas 2 e 3 até que a atividade seja concluída com êxito.

O fluxo de trabalho a seguir implementa a retry-until-success estratégia. A interface do fluxo de trabalho é implementada no `RetryActivityRecipeWorkflow` e possui um método, `runUnreliableActivityTillSuccess`, que é o ponto de entrada do fluxo de trabalho. O operador do fluxo de trabalho é implementado em `RetryActivityRecipeWorkflowImpl`, da seguinte maneira: 

```
public class RetryActivityRecipeWorkflowImpl
    implements RetryActivityRecipeWorkflow {

    @Override
    public void runUnreliableActivityTillSuccess() {
        final Settable<Boolean> retryActivity = new Settable<Boolean>();

        new TryCatch() {
            @Override
            protected void doTry() throws Throwable {
                Promise<Void> activityRanSuccessfully
                    = client.unreliableActivity();
                setRetryActivityToFalse(activityRanSuccessfully, retryActivity);
            }

            @Override
            protected void doCatch(Throwable e) throws Throwable {
                retryActivity.set(true);
            }
        };
        restartRunUnreliableActivityTillSuccess(retryActivity);
    }

    @Asynchronous
    private void setRetryActivityToFalse(
            Promise<Void> activityRanSuccessfully,
            @NoWait Settable<Boolean> retryActivity) {
        retryActivity.set(false);
    }

    @Asynchronous
    private void restartRunUnreliableActivityTillSuccess(
            Settable<Boolean> retryActivity) {
        if (retryActivity.get()) {
            runUnreliableActivityTillSuccess();
        }
    }
}
```

O fluxo de trabalho funciona da seguinte forma: 

1. `runUnreliableActivityTillSuccess` cria um objeto `Settable<Boolean>` chamado `retryActivity` que é usado para indicar se a atividade falhou e deve ser executada novamente. `Settable<T>` é derivado do `Promise<T>` e funciona da mesma forma, mas você define o valor de um objeto `Settable<T>` manualmente.

1. `runUnreliableActivityTillSuccess` implementa uma classe aninhada `TryCatch` anônima para processar todas as exceções lançadas pela atividade `unreliableActivity`. Para obter mais discussões sobre como gerenciar as exceções lançadas pelo código assíncrono, consulte [Tratamento de erros](errorhandling.md).

1. `doTry` executa a atividade `unreliableActivity`, que retorna um objeto `Promise<Void>` chamado `activityRanSuccessfully`.

1. `doTry` chama o método assíncrono `setRetryActivityToFalse`, que possui dois parâmetros:
   + `activityRanSuccessfully` recebe o objeto `Promise<Void>` retornado pela atividade `unreliableActivity`.
   + `retryActivity` recebe o objeto `retryActivity`.

   Se a `unreliableActivity` for concluída, `activityRanSuccessfully` se torna pronto e `setRetryActivityToFalse` define `retryActivity` como falso. Caso contrário, `activityRanSuccessfully` nunca se torna pronto e `setRetryActivityToFalse` não é executado.

1. Se a `unreliableActivity` lança uma exceção, a estrutura chama `doCatch` e envia-lhe o objeto de exceção. `doCatch` define `retryActivity` como verdadeiro.

1. `runUnreliableActivityTillSuccess` chama o método assíncrono `restartRunUnreliableActivityTillSuccess` e envia-lhe o objeto `retryActivity`. Como `retryActivity` é do tipo `Promise<T>`, `restartRunUnreliableActivityTillSuccess` adia a execução até que a `retryActivity` esteja pronta, o que ocorre após `TryCatch` concluir. 

1. Quando a `retryActivity` estiver pronta, `restartRunUnreliableActivityTillSuccess` extrai o valor.
   + Se o valor for `false`, a nova tentativa foi bem-sucedida. `restartRunUnreliableActivityTillSuccess` não faz nada e a sequência de repetição é encerrada.
   + Se o valor for verdadeiro, a nova tentativa falhou. `restartRunUnreliableActivityTillSuccess` chama `runUnreliableActivityTillSuccess` para executar a atividade novamente.

1. As Etapas 1 a 7 são repetias até que a `unreliableActivity` seja concluída. 

**nota**  
`doCatch` não lida com a exceção, ele simplesmente define o objeto `retryActivity` como verdadeiro para indicar que a atividade falhou. A repetição é gerenciada pelo método assíncrono `restartRunUnreliableActivityTillSuccess`, que adia a execução até que `TryCatch` seja concluído. O motivo desta abordagem é que, se você repetir uma atividade no `doCatch`, não é possível cancelá-la. Repetir a atividade em `restartRunUnreliableActivityTillSuccess` permite executar atividades canceláveis. 

## Estratégia de repetição exponencial
<a name="features-retry-exponential"></a>

Com a estratégia de repetição exponencial, a estrutura executa uma atividade falha novamente após um período especificado, N segundos. Se essa tentativa falhar, a estrutura executa a atividade novamente após 2N segundos e, em seguida, 4N segundos e assim por diante. Como o tempo de espera pode se tornar grande, normalmente você interrompe as tentativas de repetição em algum momento em vez de continuar indefinidamente.

A estrutura oferece três maneiras para implementar uma estratégia de repetição exponencial:
+ A anotação `@ExponentialRetry` é a abordagem mais simples, mas você deve definir as opções de configuração da repetição no momento da compilação.
+ A classe `RetryDecorator` permite definir a configuração de repetição durante o tempo de execução e alterá-la conforme necessário.
+ A classe `AsyncRetryingExecutor` permite definir a configuração de repetição durante o tempo de execução e alterá-la conforme necessário. Além disso, a estrutura chama um método `AsyncRunnable.run` implementado pelo usuário para executar cada tentativa de repetição.

Todas as abordagens oferecem suporte para as seguintes opções de configuração, onde os valores de tempo estão em segundos: 
+ O tempo de espera da repetição inicial.
+ O coeficiente de recuo, que é usado para computar os intervalos de repetição, da seguinte forma:

  ```
  retryInterval = initialRetryIntervalSeconds * Math.pow(backoffCoefficient, numberOfTries - 2)
  ```

  O valor padrão é 2.0.
+ O número máximo de tentativas de repetição. O valor padrão é ilimitado.
+ O intervalo máximo de repetição. O valor padrão é ilimitado.
+ O tempo de expiração. As tentativas de repetição param quando a duração total do processo excede esse valor. O valor padrão é ilimitado.
+ As exceções que acionarão o processo de repetição. Por padrão, toda exceção aciona o processo de repetição.
+ As exceções que não acionarão um processo de repetição. Por padrão, nenhuma exceção está excluída.

As seções a seguir descrevem as diversas formas para implementar uma estratégia de repetição exponencial.

### Tentativa exponencial com @ ExponentialRetry
<a name="features-retry-exponential-annotation"></a>

A forma mais simples de implementar uma estratégia de repetição exponencial para uma atividade é aplicar uma anotação `@ExponentialRetry ` à atividade na definição da interface. Se a atividade falhar, a estrutura gerencia o processo de repetição automaticamente, com base nos valores da opção especificada. O padrão básico é:

1. Aplique `@ExponentialRetry` às atividades apropriadas e especifique a configuração de repetição.

1. Se uma atividade anotada falhar, a estrutura repete automaticamente a atividade de acordo com a configuração especificada pelos argumentos da anotação. 

O operador de fluxo de trabalho `ExponentialRetryAnnotationWorkflow` implementa a estratégia de repetição exponencial usando uma anotação `@ExponentialRetry`. Ele usa uma atividade `unreliableActivity`, cuja definição de interface é implementada nas `ExponentialRetryAnnotationActivities`, da seguinte forma:

```
@Activities(version = "1.0")
@ActivityRegistrationOptions(
    defaultTaskScheduleToStartTimeoutSeconds = 30,
    defaultTaskStartToCloseTimeoutSeconds = 30)
public interface ExponentialRetryAnnotationActivities {
    @ExponentialRetry(
        initialRetryIntervalSeconds = 5,
        maximumAttempts = 5,
        exceptionsToRetry = IllegalStateException.class)
    public void unreliableActivity();
}
```

As opções `@ExponentialRetry` especificam a seguinte estratégia: 
+ Repetir somente se a atividade lançar uma `IllegalStateException`.
+ Usar um tempo de espera inicial de 5 segundos.
+ Não mais que cinco tentativas de repetição. 

A interface do fluxo de trabalho é implementada no `RetryWorkflow` e possui um método, `process`, que é o ponto de entrada do fluxo de trabalho. O operador do fluxo de trabalho é implementado em `ExponentialRetryAnnotationWorkflowImpl`, da seguinte maneira: 

```
public class ExponentialRetryAnnotationWorkflowImpl implements RetryWorkflow {
    public void process() {
        handleUnreliableActivity();
    }

    public void handleUnreliableActivity() {
        client.unreliableActivity();
    }
}
```

O fluxo de trabalho funciona da seguinte forma: 

1. `process` executa o método síncrono `handleUnreliableActivity`.

1. `handleUnreliableActivity` executa a atividade `unreliableActivity`. 

Se a atividade falhar ao lançar uma `IllegalStateException`, a estrutura executa automaticamente a estratégia de repetição especificada nas `ExponentialRetryAnnotationActivities`.

### Repetição exponencial com a classe RetryDecorator
<a name="features-retry-exponential-decorator"></a>

O uso do `@ExponentialRetry` é simples. No entanto, a configuração é estática e definida durante a compilação, portanto a estrutura usa a mesma estratégia de repetição sempre que a atividade falhar. É possível implementar uma estratégia de repetição exponencial mais flexível usando a classe `RetryDecorator`, que permite especificar a configuração durante o tempo de execução e alterá-la conforme necessário. O padrão básico é:

1. Crie e configure um objeto `ExponentialRetryPolicy` que especifica a configuração de repetição.

1. Crie um objeto `RetryDecorator` e envie o objeto `ExponentialRetryPolicy` da Etapa 1 para o construtor.

1. Aplique o objeto decorador à atividade enviando o nome de classe do cliente da atividade para o método de decoração do objeto `RetryDecorator`.

1. Execute a atividade.

Se a atividade falhar, a estrutura repete a atividade de acordo com a configuração do objeto `ExponentialRetryPolicy`. Altere a configuração de repetição conforme necessário modificando esse objeto. 

**nota**  
A anotação `@ExponentialRetry` e a classe `RetryDecorator` são mutuamente exclusivas. Não é possível usar `RetryDecorator` para substituir dinamicamente uma política de repetição especificada por uma anotação `@ExponentialRetry`. 

A implementação de fluxo de trabalho a seguir mostra como usar a classe `RetryDecorator` para implementar uma estratégia de repetição exponencial. Ela usa uma atividade `unreliableActivity` que não possui uma anotação `@ExponentialRetry`. A interface do fluxo de trabalho é implementada no `RetryWorkflow` e possui um método, `process`, que é o ponto de entrada do fluxo de trabalho. O operador do fluxo de trabalho é implementado em `DecoratorRetryWorkflowImpl`, da seguinte maneira: 

```
public class DecoratorRetryWorkflowImpl implements RetryWorkflow {
   ...
  public void process() {
      long initialRetryIntervalSeconds = 5;
      int maximumAttempts = 5;
      ExponentialRetryPolicy retryPolicy = new ExponentialRetryPolicy(
              initialRetryIntervalSeconds).withMaximumAttempts(maximumAttempts);

      Decorator retryDecorator = new RetryDecorator(retryPolicy);
      client = retryDecorator.decorate(RetryActivitiesClient.class, client);
      handleUnreliableActivity();
  }

  public void handleUnreliableActivity() {
      client.unreliableActivity();
  }
}
```

O fluxo de trabalho funciona da seguinte forma: 

1. `process` cria e configura um objeto `ExponentialRetryPolicy` ao: 
   + Enviar o intervalo inicial de repetição ao construtor.
   + Chamar o método `withMaximumAttempts` do objeto para definir o número máximo de tentativas como cinco. `ExponentialRetryPolicy` expõe outros objetos `with` que você pode usar para especificar outras opções de configuração.

1. `process` cria um objeto `RetryDecorator` chamado `retryDecorator` e envia o objeto `ExponentialRetryPolicy` da Etapa 1 ao construtor.

1. `process` aplica o decorador à atividade chamando o método `retryDecorator.decorate` e enviando-lhe o nome de classe do cliente da atividade.

1. `handleUnreliableActivity` executa a atividade. 

Se a atividade falhar, a estrutura repete-a de acordo com a configuração especificada na Etapa 1.

**nota**  
Muitos dos métodos `with` da classe `ExponentialRetryPolicy` possuem um método `set` correspondente que pode ser chamado para modificar a opção de configuração correspondente a qualquer momento: `setBackoffCoefficient`, `setMaximumAttempts`, `setMaximumRetryIntervalSeconds` e `setMaximumRetryExpirationIntervalSeconds`. 

### Repetição exponencial com a classe AsyncRetryingExecutor
<a name="features-retry-exponential-async"></a>

A classe `RetryDecorator` oferece mais flexibilidade ao configurar o processo de repetição que a `@ExponentialRetry`, mas a estrutura ainda executa as tentativas de repetição automaticamente, com base na configuração atual do objeto `ExponentialRetryPolicy`. Uma abordagem mais flexível é usar a classe `AsyncRetryingExecutor`. Além de permitir que você configure o processo de repetição durante o tempo de execução, a estrutura chama um método `AsyncRunnable.run` implementado pelo usuário para executar cada tentativa de repetição em vez de simplesmente executar a atividade.

O padrão básico é: 

1. Crie e configure um objeto `ExponentialRetryPolicy` para especificar a configuração de repetição.

1. Crie um objeto `AsyncRetryingExecutor` e envie-lhe o objeto `ExponentialRetryPolicy` e uma instância do clock do fluxo de trabalho.

1.  Implemente uma classe aninhada `TryCatch` ou `TryCatchFinally` anônima.

1. Implemente uma classe `AsyncRunnable` anônima e substitua o método `run` para implementar o código personalizado para execução da atividade.

1.  Substitua `doTry` para chamar o método `execute` do objeto `AsyncRetryingExecutor` enviar-lhe a classe `AsyncRunnable` da Etapa 4. O objeto `AsyncRetryingExecutor` chama `AsyncRunnable.run` para executar a atividade.

1. Se a atividade falhar, o objeto `AsyncRetryingExecutor` chama o método `AsyncRunnable.run` novamente, de acordo com a política de repetição especificada na Etapa 1. 

O fluxo de trabalho a seguir mostra como usar a classe `AsyncRetryingExecutor` para implementar uma estratégia de repetição exponencial. Ele usa a mesma atividade `unreliableActivity` que o fluxo de trabalho `DecoratorRetryWorkflow` discutido anteriormente. A interface do fluxo de trabalho é implementada no `RetryWorkflow` e possui um método, `process`, que é o ponto de entrada do fluxo de trabalho. O operador do fluxo de trabalho é implementado em `AsyncExecutorRetryWorkflowImpl`, da seguinte maneira: 

```
public class AsyncExecutorRetryWorkflowImpl implements RetryWorkflow {
  private final RetryActivitiesClient client = new RetryActivitiesClientImpl();
  private final DecisionContextProvider contextProvider = new DecisionContextProviderImpl();
  private final WorkflowClock clock = contextProvider.getDecisionContext().getWorkflowClock();

  public void process() {
      long initialRetryIntervalSeconds = 5;
      int maximumAttempts = 5;
      handleUnreliableActivity(initialRetryIntervalSeconds, maximumAttempts);
  }
  public void handleUnreliableActivity(long initialRetryIntervalSeconds, int maximumAttempts) {

      ExponentialRetryPolicy retryPolicy = new ExponentialRetryPolicy(initialRetryIntervalSeconds).withMaximumAttempts(maximumAttempts);
      final AsyncExecutor executor = new AsyncRetryingExecutor(retryPolicy, clock);

      new TryCatch() {
          @Override
          protected void doTry() throws Throwable {
              executor.execute(new AsyncRunnable() {
                  @Override
                  public void run() throws Throwable {
                      client.unreliableActivity();
                  }
              });
          }
          @Override
          protected void doCatch(Throwable e) throws Throwable {
          }
      };
  }
}
```

O fluxo de trabalho funciona da seguinte forma: 

1. `process` chama o método `handleUnreliableActivity` e envia-lhe as definições de configuração.

1. `handleUnreliableActivity` usa as definições de configuração da Etapa 1 para criar um objeto `ExponentialRetryPolicy`, `retryPolicy`.

1. `handleUnreliableActivity` cria um objeto `AsyncRetryExecutor`, `executor`, e envia o objeto `ExponentialRetryPolicy` da Etapa 2 e uma instância do clock do fluxo de trabalho ao construtor

1.  `handleUnreliableActivity` implementa uma classe aninhada `TryCatch` anônima e substitui os métodos `doTry` e `doCatch` para executar as tentativas de repetição e gerenciar quaisquer exceções.

1. `doTry` cria uma classe `AsyncRunnable` anônima e substitui o método `run` para implementar o código personalizado para executar a `unreliableActivity`. Por simplicidade, `run` apenas executa a atividade, mas você pode implementar abordagens mais sofisticadas conforme for apropriado.

1. `doTry` chama `executor.execute` e envia-lhe o objeto `AsyncRunnable`. `execute` chama o método `AsyncRunnable` do objeto `run` para executar a atividade.

1. Se a atividade falhar, o executor chama `run` novamente, de acordo com a configuração do objeto `retryPolicy`. 

Para obter mais discussões sobre como usar a classe `TryCatch` para gerenciar erros, consulte [AWS Flow Framework para exceções de Java](errorhandling.exceptions.md). 

## Estratégia de repetição personalizada
<a name="custom-retry-strategy"></a>

A abordagem mais flexível para repetir atividades com falha é uma estratégia personalizada, que chama recursivamente um método assíncrono que executa a tentativa de repetição, de forma muito parecida com a estratégia. retry-until-success No entanto, em vez de simplesmente executar a atividade novamente, implemente a lógica personalizada que decide se e como executar cada tentativa sucessiva de repetição. O padrão básico é: 

1. Crie um objeto de status `Settable<T>`, que é usado para indicar se a atividade falhou.

1. Implemente uma classe aninhada `TryCatch` ou `TryCatchFinally`.

1. `doTry` executa a atividade.

1. Se a atividade falhar, `doCatch` define o objeto de status para indicar que a atividade falhou.

1. Chame um método assíncrono de gerenciamento de falhas e envie-lhe o objeto de status. O método adia a execução até que `TryCatch` ou `TryCatchFinally` conclua.

1. O método de gerenciamento de falhas decide se deve repetir a atividade e, se sim, quando.

O fluxo de trabalho a seguir mostra como implementar uma estratégia de repetição personalizada. Ele usa a mesma atividade `unreliableActivity` que os fluxos de trabalho `DecoratorRetryWorkflow` e `AsyncExecutorRetryWorkflow`. A interface do fluxo de trabalho é implementada no `RetryWorkflow` e possui um método, `process`, que é o ponto de entrada do fluxo de trabalho. O operador do fluxo de trabalho é implementado em `CustomLogicRetryWorkflowImpl`, da seguinte maneira: 

```
public class CustomLogicRetryWorkflowImpl implements RetryWorkflow {
  ...
  public void process() {
      callActivityWithRetry();
  }
  @Asynchronous
  public void callActivityWithRetry() {
      final Settable<Throwable> failure = new Settable<Throwable>();
      new TryCatchFinally() {
          protected void doTry() throws Throwable {
              client.unreliableActivity();
          }
          protected void doCatch(Throwable e) {
              failure.set(e);
          }
          protected void doFinally() throws Throwable {
              if (!failure.isReady()) {
                  failure.set(null);
              }
          }
      };
      retryOnFailure(failure);
  }
  @Asynchronous
  private void retryOnFailure(Promise<Throwable> failureP) {
      Throwable failure = failureP.get();
      if (failure != null && shouldRetry(failure)) {
          callActivityWithRetry();
      }
  }
  protected Boolean shouldRetry(Throwable e) {
      //custom logic to decide to retry the activity or not
      return true;
  }
}
```

O fluxo de trabalho funciona da seguinte forma:

1. `process` chama o método assíncrono `callActivityWithRetry`.

1. `callActivityWithRetry` cria um objeto `Settable<Throwable>` chamado failure que é usado para indicar se a atividade falhou. `Settable<T>` é derivado de `Promise<T>` e funciona da mesma forma, mas você define o valor de um objeto `Settable<T>` manualmente.

1. `callActivityWithRetry` implementa uma classe aninhada `TryCatchFinally` anônima para processar todas as exceções lançadas pela `unreliableActivity`. Para obter mais discussões sobre como gerenciar as exceções lançadas pelo código assíncrono, consulte [AWS Flow Framework para exceções de Java](errorhandling.exceptions.md).

1. `doTry` executa a `unreliableActivity`.

1. Se `unreliableActivity` lança uma exceção, a estrutura chama `doCatch` e envia-lhe o objeto de exceção. `doCatch` define `failure` para o objeto de exceção, o que indica que a atividade falhou e coloca o objeto em um estado pronto.

1. `doFinally` verifica se `failure` está pronto, que será verdadeiro somente se `failure` foi definido por `doCatch`.
   + Se `failure` estiver pronto, `doFinally` não faz nada.
   + Se `failure` não estiver pronto, a atividade foi concluída e `doFinally` define failure como `null`. 

1. `callActivityWithRetry` chama o método assíncrono `retryOnFailure` e envia-lhe o failure. Como failure é do tipo `Settable<T>`, `callActivityWithRetry` adia a execução até que failure esteja pronto, o que ocorre após `TryCatchFinally` concluir.

1. `retryOnFailure` obtém o valor de failure.
   + Se failure está definido como null, a tentativa de repetição foi bem-sucedida. `retryOnFailure` não faz nada, o que encerra o processo de repetição.
   + Se failure for definido como um objeto de exceção e `shouldRetry` retornar verdadeiro, `retryOnFailure` chama `callActivityWithRetry` para repetir a atividade. 

     `shouldRetry` implementa a lógica personalizada para decidir se deve repetir uma atividade com falha. Por simplicidade, `shouldRetry` sempre retorna `true` e `retryOnFailure` executa a atividade imediatamente, mas você pode implementar uma lógica mais sofisticada conforme necessário. 

1. As etapas 2 a 8 se repetem até que `unreliableActivity` seja concluído ou `shouldRetry` decida interromper o processo. 

**nota**  
`doCatch` não lida com o processo de repetição, ele simplesmente define failure para indicar que a atividade falhou. A processo de repetição é gerenciado pelo método assíncrono `retryOnFailure`, que adia a execução até que `TryCatch` seja concluído. O motivo desta abordagem é que, se você repetir uma atividade no `doCatch`, não é possível cancelá-la. Repetir a atividade em `retryOnFailure` permite executar atividades canceláveis. 