java-restify
Search…
Retry
O java-restify oferece suporte para retry de requisições, síncronas ou assíncronas.
Por padrão, o suporte para retry é desabilitado, e deve ser explicitamente habilitado.
1
MyApi myApi = new RestifyProxyBuilder()
2
.retry()
3
.enabled()
4
.target(MyApi.class)
5
.build();
Copied!

Configuração

As configurações podem ser realizadas no próprio builder, e serão aplicadas para todos os métodos da interface:
1
MyApi myApi = new RestifyProxyBuilder()
2
.retry()
3
.enabled()
4
.configure()
5
.attempts(3) // número de tentativas (padrão: 1 (sem retry))
6
.timeout(Duration.ofMillis(10000)) // timeout máximo para as tentativas, pode ser informado também em milisegundos (opcional)
7
.backOff() // configuração de backoff
8
.delay(Duration.ofMillis(2000)) // período entre cada tentiva, pode ser informado também em milisegundos (padrão é 1000 milisegundos, aplicável apenas se attempts > 1)
9
.multiplier(1.5) // fator de multiplicação de tempo entre cada tentativa (padrão é 1, sem efeito prático)
10
.and()
11
.when(IOException.class)
12
.when(HttpStatusCode.INTERNAL_SERVER_ERROR, HttpStatusCode.BAD_GATEWAY)
13
.target(MyApi.class)
14
.build();
Copied!
Outra configuração necessária é o tipo de situação onde o retry deve ser executado. Novamente, o comportamento padrão é não aplicar nenhum tipo de retentativa, a não ser para os cenários explicitamente configurados:
1
MyApi myApi = new RestifyProxyBuilder()
2
.retry()
3
.enabled()
4
.configure()
5
// ... outras configurações que serão aplicadas quando...
6
.when(IOException.class) // ocorrerem exceções do tipo IOException
7
.when(HttpStatusCode.INTERNAL_SERVER_ERROR, HttpStatusCode.BAD_GATEWAY) // respostas HTTP com esses status codes
8
.target(MyApi.class)
9
.build();
Copied!
É possível configurar vários cenários de erro usando do método when, quantos forem necessários. Existem outras sobrecargas que permitem ajustes ainda mais finos:
1
import com.github.ljtfreitas.restify.http.client.retry.RetryCondition.EndpointResponseRetryCondition;
2
3
// condição de retry utilizando uma instância de EndpointResponse
4
EndpointResponseRetryCondition condition = response -> response.body().equals("fail") && response.headers().get("X-Fail").isPresent();
5
6
MyApi myApi = new RestifyProxyBuilder()
7
.retry()
8
.enabled()
9
.configure()
10
// ... outras configurações que serão aplicadas quando...
11
.when(condition) // a condição for satisfeita
12
.target(MyApi.class)
13
.build();
Copied!
1
import com.github.ljtfreitas.restify.http.client.retry.RetryCondition.HeadersRetryCondition;
2
3
// condição de retry utilizando a coleção de headers da resposta
4
HeadersRetryCondition condition = headers -> headers.get("X-Should-Retry").isPresent();
5
6
/* shortcuts:
7
8
condition = HeadersRetryCondition.contains("X-Should-Retry");
9
10
condition = HeadersRetryCondition.contains(Header.of("X-Should-Retry", "true")); // para verificar também o valor do header
11
*/
12
13
MyApi myApi = new RestifyProxyBuilder()
14
.retry()
15
.enabled()
16
.configure()
17
// ... outras configurações que serão aplicadas quando...
18
.when(condition) // a condição for satisfeita
19
.target(MyApi.class)
20
.build();
Copied!
1
import com.github.ljtfreitas.restify.http.client.retry.RetryCondition.StatusCodeRetryCondition;
2
3
// condição de retry utilizando o status code da resposta
4
StatusCodeRetryCondition condition = status -> status.isInternalServerError();
5
6
/* shortcuts:
7
8
condition = StatusCodeRetryCondition.any(HttpStatusCode.INTERNAL_SERVER_ERROR, HttpStatusCode.BAD_GATEWAY);
9
10
condition = StatusCodeRetryCondition.any4xx();
11
12
condition = StatusCodeRetryCondition.any5xx();
13
*/
14
MyApi myApi = new RestifyProxyBuilder()
15
.retry()
16
.enabled()
17
.configure()
18
// ... outras configurações que serão aplicadas quando...
19
.when(condition) // a condição for satisfeita
20
.target(MyApi.class)
21
.build();
Copied!
1
import com.github.ljtfreitas.restify.http.client.retry.RetryCondition.ThrowableRetryCondition;
2
3
// condição de retry utilizando a exceção
4
ThrowableRetryCondition condition = e -> (e instanceof IOException);
5
6
/* shortcuts:
7
8
condition = ThrowableRetryCondition.any(IOException.class);
9
10
condition = ThrowableRetryCondition.ioFailure();
11
*/
12
MyApi myApi = new RestifyProxyBuilder()
13
.retry()
14
.enabled()
15
.configure()
16
// ... outras configurações que serão aplicadas quando...
17
.when(condition) // a condição for satisfeita
18
.target(MyApi.class)
19
.build();
Copied!

@Retry

Também é possível aplicar configurações mais específicas no nível do método, usando a anotação @Retry. Essa anotação tem parâmetros equivalentes às configurações disponíveis no RestifyProxyBuilder.
Essa anotação só é lida e processada se o retry for habilitado, conforme demonstrado acima.
1
public interface MyApi {
2
3
@Path("/customers/{id}") @Get
4
@Retry(
5
attempts = 3, // número de tentativas (padrão: 1 (sem retry))
6
timeout = 10000, // timeout máximo para as tentativas em milisegundos (opcional)
7
on4xxStatus = true, // retry para status codes 4xx (padrão false)
8
on5xxStatus = true, // retry para status codes 5xx (padrão false)
9
onIOFailure = true, // retry para erros do tipo IOException (padrão false)
10
status = {HttpStatusCode.INTERNAL_SERVER_ERROR, HttpStatusCode.BAD_GATEWAY}, // lista de status codes para retry (padrão é nenhum)
11
exceptions = SocketException.class, // lista de exceções para retry (padrão é nenhuma)
12
backoff = @BackOff( // configurações de backoff
13
delay = 2000, // período entre cada tentativa, em milisegundos (padrão é 1000 milisegundos, aplicável apenas se attempts > 1)
14
multiplier = 1.5 // fator de multiplicação de tempo entre cada tentativa (padrão é 1, sem efeito prático)
15
)
16
)
17
Customer findCustomer(@PathParameter String id);
Copied!
Se a anotação @Retry estiver presente no topo da interface, a configuração será aplicada a todos os métodos.

Requisiçoes assíncronas

Todas as configurações demonstradas acima também se aplicam para requições assíncronas. A implementação padrão utiliza um ScheduledExecutorService, criado com uma configuração single-thread.
Caso essa configuração não atenda as necessidades da sua aplicação, é bastante simples configurar um novo ScheduledExecutorService:
1
import java.util.concurrent.Executors;
2
import java.util.concurrent.ScheduledExecutorService;
3
4
public interface MyApi {
5
6
// CompletableFuture = requisição assíncrona
7
// as retentativas também serão executas em thread separadas
8
9
@Path("/customers/{id}") @Get
10
@Retry(attempts = 3, on5xxStatus = true, backoff = @BackOff(delay = 2000))
11
CompletableFuture<Customer> findCustomer(@PathParameter String id);
12
}
13
14
ScheduledExecutorService myScheduler = Executors.newScheduledThreadPool(10);
15
16
MyApi myApi = new RestifyProxyBuilder()
17
.retry()
18
.enabled()
19
.async()
20
.scheduler(myScheduler)
21
.target(MyApi.class)
22
.build();
Copied!
Last modified 2yr ago