NoSuchMethodException in resilience4j fallback with spring boot

Viewed 2327

I am new to this circuit breaking technology. I tried to implement this technology with eureka server but get stuck at this fallback method point.

my pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.10.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.microservice</groupId>
<artifactId>inventory-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>inventory-client</name>
<description>Demo microservice project for Spring Boot</description>

<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>

<dependencies>
    <!-- <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</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-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.github.resilience4j</groupId>
        <artifactId>resilience4j-spring-boot2</artifactId>
        <version>1.3.1</version>
    </dependency>
    <dependency>
        <groupId>io.github.resilience4j</groupId>
        <artifactId>resilience4j-circuitbreaker</artifactId>
        <version>1.3.1</version>
    </dependency>
    

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

my application.properties

spring.application.name=inventory-client-app
server.port=8081

spring.cloud.circuitbreaker.resilience4j.enabled=false

resilience4j.circuitbreaker.instances.itemTypesBreaker.registerHealthIndicator=true
resilience4j.circuitbreaker.instances.itemTypesBreaker.slidingWindowSize=10
resilience4j.circuitbreaker.instances.itemTypesBreaker.permittedNumberOfCallsInHalfOpenState=3
resilience4j.circuitbreaker.instances.itemTypesBreaker.slidingWindowType=TIME_BASED
resilience4j.circuitbreaker.instances.itemTypesBreaker.minimumNumberOfCalls=20
resilience4j.circuitbreaker.instances.itemTypesBreaker.waitDurationInOpenState=50s
resilience4j.circuitbreaker.instances.itemTypesBreaker.failureRateThreshold=50
resilience4j.circuitbreaker.instances.itemTypesBreaker.eventConsumerBufferSize=10

my controller

import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;

@RestController
@RequestMapping("/inventory-client")
public class ItemTypeController {

@Autowired
RestTemplate restTemplate;


@GetMapping("/item-types")
@ResponseStatus(HttpStatus.OK)
@CircuitBreaker(name="itemTypesBreaker",fallbackMethod = "itemTypesFallBack")
public List<ItemType> getAllItemTypes(){
    List<ItemType> itemTypeList = (List<ItemType>) restTemplate.getForObject("http://inventory-catalog-app/inventory-catalog/item-types/", ItemType.class);
    return itemTypeList;
}

private String itemTypesFallBack(Throwable t){

    return "Item Catalog is down";
    
}

}

I cannot call this endpoint with fallback method, what other configuration do I missing? . Thanks in advance.

2 Answers

I have found a solution. The fallback method signatures should be like this.

private List<ItemType> itemTypesFallBack(Throwable t){
    System.out.println("Item Catalog is down");
    return null;

}

Acordly the documentation the fall back method should be placed in the same class and must have the same method signature with just ONE extra target exception parameter.

If you try to recover from NumberFormatException, the method with signature String fallback(String parameter, IllegalArgumentException exception)} will be invoked.

Normaly i create the fall back method with RuntimeException extra argument. In your case, the method will looks like:

private List<ItemType> itemTypesFallBack(RuntimeException e){
   ...
}
Related