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!



