Spring cloud gateway with Resilience4j circuit breaker
Tags: resilience4j, springcloud, java, springcloudgateway
Published: 2020-05-25 23:32:32

<!-- wp:paragraph -->
<p>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 :</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Resilience4j <a rel="noreferrer noopener" aria-label="spring boot starter (opens in a new tab)" href="https://github.com/resilience4j/resilience4j/tree/master/resilience4j-spring-boot2" target="_blank">spring boot starter</a></li><li>Spring cloud <a href="https://github.com/spring-cloud/spring-cloud-circuitbreaker/tree/master/spring-cloud-circuitbreaker-resilience4j" target="_blank" rel="noreferrer noopener" aria-label="resilience4j circuit breaker (opens in a new tab)">resilience4j circuit breaker</a></li><li>Spring <a href="https://cloud.spring.io/spring-cloud-gateway/reference/html/" target="_blank" rel="noreferrer noopener" aria-label="cloud gateway  (opens in a new tab)">cloud gateway </a></li></ul>
<!-- /wp:list -->

<!-- wp:image {"id":385,"sizeSlug":"large"} -->
<figure class="wp-block-image size-large"><img src="https://mromeh.files.wordpress.com/2019/12/banner2.jpg?w=592" alt="" class="wp-image-385"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>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.</p>
<!-- /wp:paragraph -->

<!-- wp:more -->
<!--more-->
<!-- /wp:more -->

<!-- wp:paragraph -->
<p>The whole code sample is in <a href="https://github.com/Romeh/spring-cloud-gateway-resilience4j" target="_blank" rel="noreferrer noopener" aria-label="github (opens in a new tab)">github</a> .</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>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 :</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>How to enable Resilience4j circuit-breaker in Spring cloud Gateway</li><li>How we can externally configure the defined Resilience4j circuit breaker </li><li>How we can test it by using Mock Server Test containers and the proper setup for it </li></ul>
<!-- /wp:list -->

<!-- wp:paragraph {"textColor":"vivid-cyan-blue","style":{"typography":{"fontSize":22}}} -->
<p class="has-vivid-cyan-blue-color has-text-color" style="font-size:22px">How to enable Resilience4j circuit-breaker in Spring cloud Gateway:</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You need to add the following dependencies to your spring cloud gateway application to enable Resilience4j circuit breaker integration </p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"xml"} -->
<pre class="wp-block-syntaxhighlighter-code">        &lt;dependency>
            &lt;groupId>org.springframework.cloud&lt;/groupId>
            &lt;artifactId>spring-cloud-starter-gateway&lt;/artifactId>
        &lt;/dependency>
        &lt;dependency>
            &lt;groupId>io.github.resilience4j&lt;/groupId>
            &lt;artifactId>resilience4j-spring-boot2&lt;/artifactId>
            &lt;version>1.1.0&lt;/version>
        &lt;/dependency>
        &lt;dependency>
            &lt;groupId>org.springframework.cloud&lt;/groupId>
            &lt;artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j&lt;/artifactId>
        &lt;/dependency>
        &lt;dependency>
            &lt;groupId>org.springframework.boot&lt;/groupId>
            &lt;artifactId>spring-boot-starter-actuator&lt;/artifactId>
        &lt;/dependency></pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>We have a sample back-end service rout configuration like the following which will be overridden in our test setup later :</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"groovy"} -->
<pre class="wp-block-syntaxhighlighter-code">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/(?&lt;path>.*), /$\{path}</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph {"textColor":"vivid-cyan-blue","style":{"typography":{"fontSize":22}}} -->
<p class="has-vivid-cyan-blue-color has-text-color" style="font-size:22px">How we can externally configure the defined Resilience4j circuit breaker :</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>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.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>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!</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Resilience4j external configuration will be like :</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"groovy"} -->
<pre class="wp-block-syntaxhighlighter-code">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</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>The integration between resilience4j loaded Circuit breaker registry and spring cloud ReactiveResilience4JCircuitBreakerFactory will be done as the following : </p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"java"} -->
<pre class="wp-block-syntaxhighlighter-code">	@Bean
	public ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory(CircuitBreakerRegistry circuitBreakerRegistry) {
		ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory = new ReactiveResilience4JCircuitBreakerFactory();
		reactiveResilience4JCircuitBreakerFactory.configureCircuitBreakerRegistry(circuitBreakerRegistry);
		return reactiveResilience4JCircuitBreakerFactory;
	}</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph {"textColor":"vivid-cyan-blue","style":{"typography":{"fontSize":22}}} -->
<p class="has-vivid-cyan-blue-color has-text-color" style="font-size:22px">How we can test it by using Mock Server Test containers and the proper setup for it :</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now it is time to test that integration and see how it works :</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>we will use mock server test containers to mock the target back end service reached out through the gateway </li><li>we will stub some responses </li><li>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 </li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Add the following dependencies to enable the usage of mock server </p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"xml"} -->
<pre class="wp-block-syntaxhighlighter-code">       &lt;dependency>
            &lt;groupId>org.testcontainers&lt;/groupId>
            &lt;artifactId>mockserver&lt;/artifactId>
            &lt;version>1.12.3&lt;/version>
            &lt;scope>test&lt;/scope>
        &lt;/dependency>
        &lt;dependency>
            &lt;groupId>org.mock-server&lt;/groupId>
            &lt;artifactId>mockserver-client-java&lt;/artifactId>
            &lt;version>3.10.8&lt;/version>
            &lt;scope>test&lt;/scope>
        &lt;/dependency></pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>Now you need to configure the test container starup plus injecting the custom configuration of the route after the startup of the mock server :</p>
<!-- /wp:paragraph -->

<!-- wp:syntaxhighlighter/code {"language":"java"} -->
<pre class="wp-block-syntaxhighlighter-code">@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&lt;ConfigurableApplicationContext> {
		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/(?&lt;path>.*), /$\\{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();
    }
}

</pre>
<!-- /wp:syntaxhighlighter/code -->

<!-- wp:paragraph -->
<p>Finally you can trigger test of the protected endpoint in class <a rel="noreferrer noopener" aria-label="GatewayCircuitBreakerTest (opens in a new tab)" href="https://github.com/Romeh/spring-cloud-gateway-resilience4j/blob/master/src/test/java/io/github/romeh/services/gateway/GatewayCircuitBreakerTest.java" target="_blank">GatewayCircuitBreakerTest</a> and see it is going through Resilience4j circuit-breaker by analyzing the reported events in your console :</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":389,"width":587,"height":78,"sizeSlug":"large"} -->
<figure class="wp-block-image size-large is-resized"><img src="https://mromeh.files.wordpress.com/2019/12/screenshot-2019-12-25-at-21.48.27.png?w=1024" alt="" class="wp-image-389" width="587" height="78"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph {"textColor":"vivid-cyan-blue","style":{"typography":{"fontSize":22}}} -->
<p class="has-vivid-cyan-blue-color has-text-color" style="font-size:22px">References:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Resilienc4j :https://resilience4j.readme.io/docs</li><li>Spring cloud circuit breaker :https://spring.io/projects/spring-cloud-circuitbreaker</li><li>Spring Cloud gateway :https://cloud.spring.io/spring-cloud-gateway/reference/html/</li></ul>
<!-- /wp:list -->