Conteúdo do item:

Circuit Breaker

Como evitar que uma falha de rede ou serviço se espalhe para outros serviços?

Link referência:

Sobre o pattern : https://microservices.io/patterns/reliability/circuit-breaker.html
Documentação da Biblioteca: https://resilience4j.readme.io/docs/circuitbreaker
Vídeo sobre performance: https://www.byiorio.com.br/blog/1
Vídeo sobre arquitetura do servidor: https://www.byiorio.com.br/product/5/item/21
GitHub do projeto: https://github.com/lucasmi/performance_test

Circuit Breaker

"Se você usa a arquitetura de micros serviços, às vezes, pode lhe dar com a situação de um serviço chamar o outro. Quando um serviço requisita outro de forma síncrona, há sempre a possibilidade de que o outro serviço não esteja disponível ou esteja exibindo uma latência tão alta que seja essencialmente inutilizável.
 
Recursos preciosos, como threads, podem ser consumidos no serviço chamador enquanto aguarda a resposta do outro serviço. Isso pode levar ao esgotamento de recursos, o que tornaria o serviço chamador incapaz de lidar com outras solicitações. A falha de um serviço pode potencialmente se propagar para outros serviços em todo seu ecossistema"


Dependências:
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<dependency>
			<groupId>io.github.resilience4j</groupId>
			<artifactId>resilience4j-spring-boot2</artifactId>
                        <version>1.7.1</version>
		</dependency>

		<dependency>
			<groupId>io.github.resilience4j</groupId>
			<artifactId>resilience4j-reactor</artifactId>
			<version>1.7.1</version>
		</dependency>


Application.properties

#Criando para ser alterado no CircuitConfig
resilience4j.circuitbreaker.instances.externalServiceFoo.slidingWindowType=COUNT_BASED

Config:
package br.com.byiorio.performance_test.infra;

import java.time.Duration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.SlidingWindowType;
import io.github.resilience4j.common.circuitbreaker.configuration.CircuitBreakerConfigCustomizer;

@Configuration
public class CircuitConfig {

    // https://resilience4j.readme.io/docs/circuitbreaker
    @Bean
    public CircuitBreakerConfigCustomizer externalServiceFooCircuitBreakerConfig() {
        return CircuitBreakerConfigCustomizer
                .of("externalServiceFoo",
                        builder -> builder.slidingWindowSize(10)
                                .slidingWindowType(SlidingWindowType.COUNT_BASED)
                                .waitDurationInOpenState(Duration.ofSeconds(5))
                                .minimumNumberOfCalls(5)
                                .failureRateThreshold(50.0f));
    }
}


Controller Advice:

package br.com.byiorio.performance_test.infra;

import java.util.LinkedHashMap;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.reactive.function.client.WebClientRequestException;

@ControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> handleException(Exception ex, WebRequest request) {

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("errorCode", "122");
        body.put("errorMessage", ex.getMessage());

        return new ResponseEntity<>(body, HttpStatus.SERVICE_UNAVAILABLE);
    }

    @ExceptionHandler(WebClientRequestException.class)
    public ResponseEntity<Object> handleException(WebClientRequestException ex, WebRequest request) {

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("errorCode", "122");
        body.put("errorMessage", ex.getMessage());

        return new ResponseEntity<>(body, HttpStatus.SERVICE_UNAVAILABLE);
    }

}

Anotação:

 @CircuitBreaker(name = "externalServiceFoo")
    public Mono<Object> usandoWebClientSemBlockCircuit(Integer accountNumber) {

        // Primeira Chamada
        Mono<CardResponse> card = httpClientLocalhost
                .get()
                .uri(HTTP_LOCALHOST_9090.concat(accountNumber.toString()).concat("/card"))
                .retrieve()
                .bodyToMono(CardResponse.class);

        // Segunda Chamada
        Mono<StatusResponse> status = httpClientLocalhost
                .get()
                .uri(HTTP_LOCALHOST_9091.concat(accountNumber.toString()).concat("/status"))
                .retrieve()
                .bodyToMono(StatusResponse.class);

        // Execução em paralelo
        return Mono.zip(card, status)
                .map(respostas -> {

                    return BalanceResponse.builder()
                            .status(respostas.getT2().getCode())
                            .cardNumber(respostas.getT1().getCardNumber())
                            .balance(this.getBalance(accountNumber))
                            .build();
                });

    }


Circuit Breaker



Redirecionar para https://www.byiorio.com.br/product/7/item/26