Search code examples
javaspring-bootresilience4j

Can't get Resilience4j @RateLimiter to work with Spring Boot


I can't seem to get Resilience4j @RateLimiter to work with Spring Boot.

Below is the code

@Log4j2
@Component
class Resilience4jDemo implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        for (int i = 0; i < 100; i++) {
            callBackendA();
        }
    }

    @RateLimiter(name = "backendA")
    private void callBackendA() {
        log.info("Calling ");
    }
}

application.yaml file

resilience4j.ratelimiter:
  instances:
    backendA:
      limitForPeriod: 1
      limitRefreshPeriod: 10s
      timeoutDuration: 0

pom.xml

<!-- https://mvnrepository.com/artifact/io.github.resilience4j/resilience4j-spring-boot2 -->
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.7.1</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.6.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.6.0</version>
</dependency>

There is no rate limit being done. Can't figure out what I missed.


Solution

  • I don't have an experience with Resilience4j but it looks like you're trying to use spring-aop here. This works with runtime generated proxy that wraps an original class providing additional functionality (Rate limiting in this case).

    If so, you can't annotate the private method of the class because it won't be detected and processed by the proxy generation mechanism.

    Instead consider creating another bean and expose its functionality as a public method:

    public interface Backend {
       void callBackendA();
    }
    
    @Component // this is a spring bean!
    @Log4j2
    public class LoggingBackendImpl implements Backend {
       @RateLimiter(name = "backendA")
       public void callBackendA() {
          log.info("calling backend");
       }
    }
    
    
    @Component
    class Resilience4jDemo implements CommandLineRunner {
        @Autowired
        Backend backend;  // this has to be managed by spring 
    
        @Override
        public void run(String... args) throws Exception {
            for (int i = 0; i < 100; i++) {
                backend.callBackendA();
            }
        }
    }