Spring cloud gateway with Resilience4j circuit breaker

romeh

MRomeh

Posted on May 25, 2020

Spring cloud gateway with Resilience4j circuit breaker

In that post we will cover how to use resilience4j circuit breaker with spring cloud gateway for the back-end services behind the gateway by utilizing the following :

In that post we will show the case of how you can mix the usage of the Resilience4j spring boot starter and spring cloud circuit breaker starter so you can configure externally through spring configuration your circuit breakers definitions if you do not want to use the code configuration approach provided by Spring cloud circuit breaker starter through Customizers.

The whole code sample is in github .

First we are create spring cloud gateway application with one micro service route configuration which we will use to enable circuit breaker resilience over it by applying Resilience4j circuit breaker protection over it so we will cover the following points :

  • How to enable Resilience4j circuit-breaker in Spring cloud Gateway
  • How we can externally configure the defined Resilience4j circuit breaker
  • How we can test it by using Mock Server Test containers and the proper setup for it

How to enable Resilience4j circuit-breaker in Spring cloud Gateway:

You need to add the following dependencies to your spring cloud gateway application to enable Resilience4j circuit breaker integration

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-spring-boot2</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

We have a sample back-end service rout configuration like the following which will be overridden in our test setup later :

spring:
  application:
    name: gateway-service
  output.ansi.enabled: ALWAYS
  cloud:
    gateway:
      routes:
        - id: test-service-withResilient4j
          uri: http://localhost:8091
          predicates:
            - Path=/testService/**
          filters:
            - RewritePath=/testService/(?<path>.*), /$\{path}

How we can externally configure the defined Resilience4j circuit breaker :

Now Spring cloud circuit breaker starter allow you to configure your Resilience4j circuit breaker definition through Customizer usage which is code first approach but what If you want to have it externally configured so you can control the configuration externally through distributed configuration service , here Resilience4j spring boot starter come to play which enable the external spring configuration of your circuit-breakers.

Spring boot starter of resilience4j will create CircuitBreakerRegistery bean based into your external configuration then you can inject it to the resilience4j factory of spring cloud starter to enable that integration and that is it!

Resilience4j external configuration will be like :

resilience4j.circuitbreaker:
  configs:
    default:
      slidingWindowSize: 10
      minimumNumberOfCalls: 5
      permittedNumberOfCallsInHalfOpenState: 3
      automaticTransitionFromOpenToHalfOpenEnabled: true
      waitDurationInOpenState: 2s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      recordExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
      ignoreExceptions:
        - java.lang.IllegalStateException
    shared:
      slidingWindowSize: 100
      permittedNumberOfCallsInHalfOpenState: 30
      waitDurationInOpenState: 1s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10
      ignoreExceptions:
        - java.lang.IllegalStateException
  instances:
    backendA:
      baseConfig: default
    backendB:
      slidingWindowSize: 10
      minimumNumberOfCalls: 10
      permittedNumberOfCallsInHalfOpenState: 3
      waitDurationInOpenState: 1s
      failureRateThreshold: 50
      eventConsumerBufferSize: 10

The integration between resilience4j loaded Circuit breaker registry and spring cloud ReactiveResilience4JCircuitBreakerFactory will be done as the following :

   @Bean
    public ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory(CircuitBreakerRegistry circuitBreakerRegistry) {
        ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory = new ReactiveResilience4JCircuitBreakerFactory();
        reactiveResilience4JCircuitBreakerFactory.configureCircuitBreakerRegistry(circuitBreakerRegistry);
        return reactiveResilience4JCircuitBreakerFactory;
    }

How we can test it by using Mock Server Test containers and the proper setup for it :

Now it is time to test that integration and see how it works :

  • we will use mock server test containers to mock the target back end service reached out through the gateway
  • we will stub some responses
  • then trigger the test and monitor the logs to see how the ciruitbreaker react and off course you can get a lot of metrics through Resilience4j supported metrics exposure and events

Add the following dependencies to enable the usage of mock server

       <dependency>
            <groupId>org.testcontainers</groupId>
            <artifactId>mockserver</artifactId>
            <version>1.12.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mock-server</groupId>
            <artifactId>mockserver-client-java</artifactId>
            <version>3.10.8</version>
            <scope>test</scope>
        </dependency>

Now you need to configure the test container starup plus injecting the custom configuration of the route after the startup of the mock server :

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = {GatewayCircuitBreakerTest.Initializer.class})
public class GatewayCircuitBreakerTest {

    private static final Logger LOGGER = LoggerFactory.getLogger(GatewayCircuitBreakerTest.class);
    private static MockServerContainer mockServerContainer;

    static {
        mockServerContainer = new MockServerContainer();
        mockServerContainer.start();

    }

    static class Initializer
            implements ApplicationContextInitializer {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues.of(
                    "spring.cloud.gateway.routes[0].id=test-service-withResilient4j",
                    "spring.cloud.gateway.routes[0].uri=" + mockServerContainer.getEndpoint(),
                    "spring.cloud.gateway.routes[0].predicates[0]=" + "Path=/testService/**",
                    "spring.cloud.gateway.routes[0].filters[0]=" + "RewritePath=/testService/(?.*), /$\\{path}",
                    "spring.cloud.gateway.routes[0].filters[1].name=" + "CircuitBreaker",
                    "spring.cloud.gateway.routes[0].filters[1].args.name=" + "backendA",
                    "spring.cloud.gateway.routes[0].filters[1].args.fallbackUri=" + "forward:/fallback/testService"
            ).applyTo(configurableApplicationContext.getEnvironment());
        }
    }

    private MockServerClient client = new MockServerClient(mockServerContainer.getContainerIpAddress(), mockServerContainer.getServerPort());
    @Autowired
    private TestRestTemplate template;

    @AfterClass
    public static void close(){
        mockServerContainer.close();
    }
}

Finally you can trigger test of the protected endpoint in class GatewayCircuitBreakerTest and see it is going through Resilience4j circuit-breaker by analyzing the reported events in your console :

References:

  • Resilienc4j :https://resilience4j.readme.io/docs
  • Spring cloud circuit breaker :https://spring.io/projects/spring-cloud-circuitbreaker
  • Spring Cloud gateway :https://cloud.spring.io/spring-cloud-gateway/reference/html/
💖 💪 🙅 🚩
romeh
MRomeh

Posted on May 25, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related