As configurações podem ser realizadas no próprio builder, e serão aplicadas para todos os métodos da interface:
MyApi myApi =newRestifyProxyBuilder().retry().enabled().configure().attempts(3) // número de tentativas (padrão: 1 (sem retry)).timeout(Duration.ofMillis(10000)) // timeout máximo para as tentativas, pode ser informado também em milisegundos (opcional).backOff() // configuração de backoff.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).multiplier(1.5) // fator de multiplicação de tempo entre cada tentativa (padrão é 1, sem efeito prático).and().when(IOException.class).when(HttpStatusCode.INTERNAL_SERVER_ERROR,HttpStatusCode.BAD_GATEWAY).target(MyApi.class).build();
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:
MyApi myApi =newRestifyProxyBuilder().retry().enabled().configure()// ... outras configurações que serão aplicadas quando....when(IOException.class) // ocorrerem exceções do tipo IOException.when(HttpStatusCode.INTERNAL_SERVER_ERROR,HttpStatusCode.BAD_GATEWAY) // respostas HTTP com esses status codes.target(MyApi.class).build();
É 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:
importcom.github.ljtfreitas.restify.http.client.retry.RetryCondition.EndpointResponseRetryCondition;// condição de retry utilizando uma instância de EndpointResponseEndpointResponseRetryCondition condition = response ->response.body().equals("fail") &&response.headers().get("X-Fail").isPresent();MyApi myApi =newRestifyProxyBuilder().retry().enabled().configure()// ... outras configurações que serão aplicadas quando....when(condition) // a condição for satisfeita.target(MyApi.class).build();
importcom.github.ljtfreitas.restify.http.client.retry.RetryCondition.HeadersRetryCondition;// condição de retry utilizando a coleção de headers da respostaHeadersRetryCondition condition = headers ->headers.get("X-Should-Retry").isPresent();/* shortcuts: condition = HeadersRetryCondition.contains("X-Should-Retry"); condition = HeadersRetryCondition.contains(Header.of("X-Should-Retry", "true")); // para verificar também o valor do header*/MyApi myApi =newRestifyProxyBuilder().retry().enabled().configure()// ... outras configurações que serão aplicadas quando....when(condition) // a condição for satisfeita.target(MyApi.class).build();
importcom.github.ljtfreitas.restify.http.client.retry.RetryCondition.StatusCodeRetryCondition;// condição de retry utilizando o status code da respostaStatusCodeRetryCondition condition = status ->status.isInternalServerError();/* shortcuts: condition = StatusCodeRetryCondition.any(HttpStatusCode.INTERNAL_SERVER_ERROR, HttpStatusCode.BAD_GATEWAY); condition = StatusCodeRetryCondition.any4xx(); condition = StatusCodeRetryCondition.any5xx();*/MyApi myApi =newRestifyProxyBuilder().retry().enabled().configure()// ... outras configurações que serão aplicadas quando....when(condition) // a condição for satisfeita.target(MyApi.class).build();
importcom.github.ljtfreitas.restify.http.client.retry.RetryCondition.ThrowableRetryCondition;// condição de retry utilizando a exceçãoThrowableRetryCondition condition = e -> (e instanceof IOException);/* shortcuts: condition = ThrowableRetryCondition.any(IOException.class); condition = ThrowableRetryCondition.ioFailure();*/MyApi myApi =newRestifyProxyBuilder().retry().enabled().configure()// ... outras configurações que serão aplicadas quando....when(condition) // a condição for satisfeita.target(MyApi.class).build();
@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.
publicinterfaceMyApi { @Path("/customers/{id}") @Get @Retry( attempts =3,// número de tentativas (padrão: 1 (sem retry)) timeout =10000,// timeout máximo para as tentativas em milisegundos (opcional) on4xxStatus =true,// retry para status codes 4xx (padrão false) on5xxStatus =true,// retry para status codes 5xx (padrão false) onIOFailure =true,// retry para erros do tipo IOException (padrão false) status = {HttpStatusCode.INTERNAL_SERVER_ERROR,HttpStatusCode.BAD_GATEWAY},// lista de status codes para retry (padrão é nenhum) exceptions =SocketException.class,// lista de exceções para retry (padrão é nenhuma) backoff = @BackOff( // configurações de backoff delay =2000,// período entre cada tentativa, em milisegundos (padrão é 1000 milisegundos, aplicável apenas se attempts > 1) multiplier =1.5// fator de multiplicação de tempo entre cada tentativa (padrão é 1, sem efeito prático) ) )CustomerfindCustomer(@PathParameterString id);
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: