Ôoopaaa, Bora Praticar Circuit Break e Feigh? Nesta prática vamos criar uma API para consultar endereços por cep, aprova de balas rsrs.
Nossa, criar uma API para consultar endereço por cep, já existem vááááárias com este serviço. Contudo, se a API que for escolhida por algum motivo não estiver disponível, a API que estiver utilizando o serviço vai deixar de exibir o endereço. Em um cenário real, existem muitos negócios que de maneira alguma podem deixar de retornar o endereço desejado. Por exemplo, uma venda onde é preciso informar o endereço de entrega. Então para resolver um problema como esse, vamos utilizar dois serviços que fornecem o endereço em sua resposta, para comunicação entre as APIs o Feign e o micro service patterns de resiliência Circuit Breaker.
Para esboçar o nosso objetivo, abaixo temos a representação das APIs envolvidas nesta prática. Onde a api-endereco criaremos passo a passo e as APIs viacep e brasil vamos consumir seus serviços.
O circuito com estado fechado (close state) demonstra que as requisições da pi-endereco estão sendo respondidas pela api-viacep sem erros.
O circuito com estado aberto(open state) por outro lado, indica que as requisições da api-endereco estão sendo respondidas pela api-viacep com erros. Desta forma, o circuito abre e passa a fazer requisições do serviço da brasil-api.
Já o circuito com estado meio aberto (half state) é inicializado ao finalizar do tempo definido para o circuito se manter com estado aberto (open state), nesse estado é realizado uma analise das requisições ou tempo e de acordo com o resultado, no caso de sucesso retornar para o estado fechado(state close), porém, no caso de falha é realizado a transição do circuito para o estado aberto(open state) novamente.
Uma observação, ambas as APIs viacep e brasilapi são muito estáveis e estão sendo utilizadas apenas com o objetivo de demonstração do projeto Bora Praticar.
Chega de Blablaba e “Bora Praticar”
Vamos começar criando um projeto no Spring Initializr:

Dependências necessárias e que devem ser incluídas na criação do projeto e que podem ser observadas no arquivo pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
No arquivo de configuração src/main/resources/application.yml adicione as seguinte configurações:
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: health
health:
circuitbreakers:
enabled: true
resilience4j:
circuitbreaker:
instances:
endereco:
slidingWindowType: COUNT_BASED
registerHealthIndicator: true
failureRateThreshold: 50
minimumNumberOfCalls: 5
automaticTransitionFromOpenToHalfOpenEnabled: true
waitDurationInOpenState: 60s
permittedNumberOfCallsInHalfOpenState: 3
Detalhes das configurações do Circuit Break que está sendo utilizado nesta prática:
-
- health — para verificar o status da API em execução.
-
- resilience4j — para habilitar as configurações do circuit breaker.
-
- slidingWindowType — tipo de Circuit Breaker COUNT_BASED, baseado na quantidade de requisições.
-
- registerHealthIndicator — exibir a instance endereco no health check.
-
- failureRateThreshold — definido 50% a taxa limite de falha para que o CircuitBreaker faça a transição para o estado circuito aberto (open state).
-
- minimumNumberOfCalls — definido a quantidade de 5 requisições para analise do circuito.
-
- automaticTransitionFromOpenToHalfOpenEnabled — transições automáticas de estado (state) habilitada.
-
- waitDurationInOpenState — definido 60 segundos a duração do estado circuito aberto(open state), para evitar chamadas no serviço que apresenta erros dentro dos 60 segundos.
-
- permittedNumberOfCallsInHalfOpenState —definido 3 requisições para analise no estado meio aberto (half open state).
Na api-endereco vamos criar os DTOs, interfaces, service, clients e controller.
CepDTO é classe com os campos que vamos devolver na resposta em nosso serviço de consulta de cep:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CepDTO {
private String cep;
private String logradouro;
private String cidade;
private String estado;
private String bairro;
}
EnderecoViaCepDTO é classe com os campos da resposta do serviço get da API viacep e o método to é utilizado para converter a resposta em um objeto CepDTO:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EnderecoViaCepDTO {
private String cep;
private String logradouro;
private String complemento;
private String bairro;
private String localidade;
private String uf;
public CepDTO to(){
return CepDTO.builder()
.cep(this.cep)
.logradouro(this.logradouro)
.estado(this.uf)
.bairro(this.bairro)
.cidade(this.localidade)
.build();
}
}
ViaCepClient é a interface que possibilita a comunicação com o serviço externo de pesquisa de endereço por cep da API viacep.
Rota GET do serviço da API viacep: https://viacep.com.br/ws/{cep}/json/
@FeignClient(name = "viacep", url = "https://viacep.com.br")
public interface ViaCepClient {
@GetMapping("/ws/{cep}/json")
EnderecoViaCepDTO findEndereco(
@PathVariable() String cep);
}
Anotações que utilizamos nesta interface:
-
- @FeignClient — definimos o nome do client e a url da rota principal do serviço de pesquisa de endereço por cep da API viacep.
-
- @GetMapping — definimos o complemento da rota principal, mais o parâmetro “{cep}” .
EnderecoBrasilApiDTO é classe com os campos da resposta do serviço get da API brasilapi e o método to é utilizado para converter a resposta em um objeto CepDTO:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EnderecoBrasilApiDTO {
private String cep;
private String street;
private String neighborhood;
private String city;
private String state;
public CepDTO to(){
return CepDTO.builder()
.cep(this.cep)
.logradouro(this.street)
.estado(this.state)
.bairro(this.neighborhood)
.cidade(this.city)
.build();
}
}
BrasilApiClient é a interface que possibilita a comunicação com o serviço externo de pesquisa de endereço por cep da API brasilapi.
Rota GET do serviço da API brasilapi: https://brasilapi.com.br/api/cep/v1/{cep}
@FeignClient(name = "brasilApi", url = "https://brasilapi.com.br/")
public interface BrasilApiClient {
@GetMapping("/api/cep/v1/{cep}")
EnderecoBrasilApiDTO findEndereco(
@PathVariable("cep") String cep);
}
Anotações:
-
- @FeignClient definimos o nome do client e a url da rota principal do serviço de pesquisa de endereço por cep da API brasilapi.
-
- @GetMappin definimos o complemento da rota principal, mais o parâmetro “{cep}” .
CepService é a interface que definimos o método de pesquisa por cep para implementação, ou seja contrato do nosso objetivo:
public interface CepService {
CepDTO findEndereco(String cep);
}
CepServiceImpl é a classe que está o nosso objetivo “Regra de negócio”, que é pesquisar endereço por CEP aprova de bala, rsrsr de falha, tecnicamente falando resiliênte. Para seguir o contrato tem o objetivo de implementar a interface CepService e consequentemente é obrigada a implementar o método findEndereco seguindo o contrato:
@Service
@RequiredArgsConstructor
public class CepServiceImpl implements CepService {
private final ViaCepClient viaCepClient;
private final ApiBrasilClient apiBrasilClient;
@Override
@CircuitBreaker(name = "endereco", fallbackMethod = "fallBackFindEndereco")
public CepDTO findEndereco(String cep) {
return viaCepClient.findEndereco(cep)
.to();
}
public CepDTO fallBackFindEndereco(String cep, Exception e){
return brasilApiClient.findEndereco(cep).to();
}
}
Anotações:
-
- @Service definimos a classe como provedor de serviço e o Spring vai detectar automaticamente quando uma outra classe fizer referencia para utilização da classe e seus métodos.
-
- @RequiredArgsConstructor é uma forma de fazer a injeção de dependência pelo construtor. Se você não sabia disso, sugiro o vídeo Spring Boot e Dependence Injection do canal Bora Praticar.
-
- @Override sinaliza que o método em questão é a implementação do método da interface CepService.
-
- @CircuitBreaker definimos o nome endereco, assim podemos ter regras de circuit breaker especificas para o método findEndereco, em seguida informamos o método fallBackFindEndereco que é o substituto (fallback) em caso de falha.
Métodos:
-
- findEndereco é o método principal de pesquisa de endereço por cep, que utiliza o método de pesquisa findEndereco da interface ViaCepClient. Ressaltando que este método é utilizado quando circuito está com estado fechado(state close) ou meio aberto(half open).
-
- fallBackFindEndereco é o método do fluxo alternativo que utiliza o método de pesquisa de endereço findEndereco da interface BrasilApiClient. Reforçando, que este método é invocado caso o método principal ocorra alguma falha(exception), onde o circuito estará com o estado aberto(state open).
Controller:
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/endereco")
public class EnderecoController {
private final CepService cepService;
@GetMapping("/{cep}")
public CepDTO getEndereco(@PathVariable("cep") String cep) {
return cepService.findEndereco(cep);
}
}
Anotações:
-
- @RestController define a classe como um controlador de requisições http.
-
- @RequestMapping indica a rota principal do controlador criado.
-
- @GetMapping é informado o complemento da rota principal para acessar o método de pesquisar endereço por cep com o parâmetro {cep} que será recebido na requisição.
-
- @PathVariable especifica a variável que será informada no complemento da rota, que neste caso é o cep para a pesquisa do endereço.
Método:
-
- getEndereco é responsável por receber a requisição de pesquisa de endereço por cep, recebendo como parâmetro a variável cep e repassando para o método findEndereco do service cepService, onde será executado as implementações que realizamos anteriormente e seguida obterá o retorno magicamente com o endereço correspondente ao cep informado na requisição.
Pesquisando o endereço do cep 28976005 no Postman:
GET: localhost:8080/api/endereco/28976005
Consultando o estado do circuit breaker na API:
GET: http://localhost:8080/actuator/health
Resposta(response) para o fluxo normal circuito com estado fechado(state close):
"status": "UP",
"components": {
"circuitBreakers": {
"status": "UP",
"details": {
"endereco": {
"status": "UP",
"details": {
"failureRate": "-1.0%",
"failureRateThreshold": "50.0%",
"slowCallRate": "-1.0%",
"slowCallRateThreshold": "100.0%",
"bufferedCalls": 4,
"slowCalls": 0,
"slowFailedCalls": 0,
"failedCalls": 3,
"notPermittedCalls": 0,
"state": "CLOSED"
}
}
}
}
Resposta(response) para o fluxo alternativo, circuito com estado aberto(state open):
"status": "UP",
"components": {
"circuitBreakers": {
"status": "UNKNOWN",
"details": {
"endereco": {
"status": "CIRCUIT_OPEN",
"details": {
"failureRate": "100.0%",
"failureRateThreshold": "50.0%",
"slowCallRate": "0.0%",
"slowCallRateThreshold": "100.0%",
"bufferedCalls": 3,
"slowCalls": 0,
"slowFailedCalls": 0,
"failedCalls": 3,
"notPermittedCalls": 0,
"state": "OPEN"
}
}
}
}
Resposta(response) para o fluxo de analise do circuito com estado meio aberto(half open):
"status": "UP",
"components": {
"circuitBreakers": {
"status": "UNKNOWN",
"details": {
"endereco": {
"status": "CIRCUIT_HALF_OPEN",
"details": {
"failureRate": "-1.0%",
"failureRateThreshold": "50.0%",
"slowCallRate": "-1.0%",
"slowCallRateThreshold": "100.0%",
"bufferedCalls": 0,
"slowCalls": 0,
"slowFailedCalls": 0,
"failedCalls": 0,
"notPermittedCalls": 0,
"state": "HALF_OPEN"
}
}
}
}
Portanto, você pode usar o Circuit Breaker para melhorar a tolerância a falhas e a resiliência da arquitetura de microsserviços. Além disso, evitar a cascata de falhas em outros microsserviços.
Então, esse é o fim desta prática neste artigo, espero que tenham gostado e não esqueça Bora Praticar.
Video passo a passo desta pratica .. em construção
Git do Projeto .. em construção
Referências:
-
- Circuit Breaker — https://resilience4j.readme.io/docs/circuitbreaker
-
- Circuit Breaker — https://spring.io/projects/spring-cloud-circuitbreaker
-
- Resiliência — https://resilience4j.readme.io/docs/getting-started-3
-
- API viacep — https://viacep.com.br/
-
- API brasilapi — https://brasilapi.com.br/
Código Limpo
Habilidades práticas do Agile Software
Dica Sete Devs para você que quer ser um profissional diferenciado e ser reconhecido no mercado de desenvolvimento de software.
Parabéns pela iniciativa meninos, que esse projeto alcance muitas pessoas e os levem a voos bem altos. Acompanho a trajetória de vocês, desejo muito sucesso, saúde e sabedoria!
Abraços, grandes DEV’S!
Parabéns ótimo conteúdo ☺️