Search code examples
javaspringspring-bootcachingresilience4j

RateLimiter only works attached to certain methods


My method requires two API calls, and is decorated with Spring Boot's @Cacheable as well as Resilience4j's @RateLimiter (link to doc):

    @Cacheable(value = "getProjectFile")
    @RateLimiter(name = "getProjectFile")
    public Optional<String> getProjectFile(String projectName) {
        return getFileName(projectName).flatMap(this::getProjectFileFromFileName);
    }

    private Optional<String> getFileName(String projectName) {
        String url = getUrlFromProjectName(projectName);
        return Optional.ofNullable(restTemplate.getForObject(url, String.class));
    }

    private Optional<String> getProjectFileFromFileName(String fileName) {
        String url = getUrlFromFileName(fileName);
        return Optional.ofNullable(restTemplate.getForObject(url, String.class));
    }

Both annotations work perfectly - but the rate limiter turns on even when accessing cached values, slowing down my programme unnecessarily.

To fix this, I tried moving the @RateLimiter annotation to getFileName, getProjectFileFromFileName, or both - but all of a sudden it stops working (the code compiles, but requests are too frequent).

Why does @RateLimiter work on the first function, but not the second or third? And how can I get the rate limiter inside the cached function?


Solution

  • Because of Spring AOP annotations don't work when you call a method, which is annotated, locally from the same class (bean), because then the PROXY is bypassed.

    @Cacheable and @RateLimiter on the same method might not work, because of the Spring AOP Aspect order. See: https://docs.spring.io/spring-framework/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html#aop-ataspectj-advice-ordering

    You can configure the order of the RateLimiter globally, but it might be better to move the method getFileName into another Bean und only use @RateLimiter.