Olá, no artigo anterior, nós consumimos um serviço utilizando o Feig para fazer uma busca por um determinado CEP, mas nem tudo são flores e esse serviço pode estar fora do ar e a requisição não ser completada. Aí, teremos um problema, mas quase tudo tem solução e para esse problemas temos o Hystrix.
O Hystrix implementa o padrão Circuit Breaker, que de forma bem rápida é um failover para chamadas entre micro serviços, ou seja, caso um micro serviço estiver fora do ar um método de fallback é chamado e aquela enxurrada de falhas é evitada.
Vamos usar o exemplo do artigo anterior (baixe o código aqui). Bom, o que vai ser feito é o seguinte, todas as requisições realizadas com sucesso vão ter os seus dados salvos em um MongoDB (poderia ser um Redis, ou deveria ser, mas o Mongo já estava aqui na máquina rs) e caso não seja fechada a conexão com o Postmon, será feita uma busca no MongoDB, se mesmo assim não for encontrada nenhuma informação para aquele CEP ai retornará um erro, afinal não se pode fazer milagre.
Agora é hora de colocar a mão no código. Primeiramente, é preciso adicionar as libs do Hystrix e do Spring Data MongoDB no projeto, basta adicionar isso no pom.xml.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
Dependências adicionadas, é hora de colocar as anotações do mongo na classe de response para que ela possa ser salva, veja como ela tem que ficar:
import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @Data @Document public class CepResponse { @Id private String cep; private String logradouro; private String bairro; private String cidade; private String estado; }
Agora, essa classe já pode ser salva no Mongo, o atributo “cep” é o Id e fica fácil fazer busca e o campo é automaticamente indexado.
Agora é hora de criar o repositório para esse documento do Mongo, para isso é só criar uma interface igual a exibida abaixo:
import br.com.easy.cep.integration.CepResponse; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; @Repository public interface CepRepository extends PagingAndSortingRepository<CepResponse, String> {} Após a interface criada é preciso salvar os dados quando a chamada for efetuada com sucesso, para isso é só alterar o serviço rest e deixá-lo assim: import br.com.easy.cep.integration.CepResponse; import br.com.easy.cep.integration.CepService; import br.com.easy.cep.repository.CepRepository; import lombok.AllArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; @RestController @AllArgsConstructor @RequestMapping("v1/ceps") public class CepRestService { private final CepService cepService; private final CepRepository cepRepository; @ResponseStatus(HttpStatus.OK) @RequestMapping(value = "/{cep}", method = RequestMethod.GET) public CepResponse getCep(@PathVariable String cep) { return cepRepository.save(cepService.getCep(cep)); } }
Feito isso, os dados retornados vão ser salvos no Mongo e podem ser utilizados caso algum problema aconteça com a chamada da API (Postmon), mas ainda assim pode ser que não tenhamos a informação buscada então vou criar uma exception “bonita” para que ela seja exibida no momento da falha da falha rs.
import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ResponseStatus; @ResponseStatus(HttpStatus.NOT_FOUND) public class ResourceNotFoundException extends RuntimeException {}
Por último, é só criar a classe que será chamada no caso de erro na integração e avisar o Feign que um fallback foi configurado, então, para isso é só criar uma nova classe que implementa a interface do Feig:
import br.com.easy.cep.exception.ResourceNotFoundException; import br.com.easy.cep.repository.CepRepository; import lombok.AllArgsConstructor; import org.springframework.stereotype.Component; import static java.util.Objects.isNull; @Component @AllArgsConstructor public class CepServiceFallback implements CepService { private final CepRepository cepRepository; @Override public CepResponse getCep(String cep) { CepResponse cepResponse = cepRepository.findOne(cep); if(isNull(cepResponse)) { throw new ResourceNotFoundException(); } return cepResponse; } }
O que essa classe faz é buscar no Mongo e caso não encontre ela devolve uma exception. Agora, para avisar o Feign do fallback, basta adicionar o parâmetro fallback na anotação FeigClient:
import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @FeignClient(name = "cepService", url = "http://api.postmon.com.br", fallback = CepServiceFallback.class) public interface CepService { @RequestMapping("/v1/cep/{cep}") CepResponse getCep(@PathVariable("cep") String cep); }
A configuração do tempo de timeout é definida no application.propertie ou application.yaml como exemplificado abaixo:
hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 200
Para que sua aplicação habilite o Hystrix e seu Dashboard é preciso adicionar duas anotações na sua classe de startup:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @EnableHystrix @EnableFeignClients @SpringBootApplication @EnableHystrixDashboard public class EasyCepApplication { public static void main(String[] args) { SpringApplication.run(EasyCepApplication.class, args); } }
E é isso! Agora, a aplicação tem uma tolerância maior a falha e você pode dormir um pouco mais tranquilo, espero que tenham gostado do artigo e qualquer dúvida é só comentar.
Até o próximo!