Why is bucket4j not working with caffeine

125 views Asked by At

I am trying to implement bucket4j and it is working on a default non customized cache (jCache I guess).

spring:
...
  cache:
    cache-names: rate_limit_buckets

bucket4j:
  enabled: true
  filters:
    - cache-name: rate_limit_bucketss
      url: /api/notification-admin/images
      rate-limits:
        - cache-key: getRemoteAddr()
          bandwidths:
            - capacity: 1
              time: 100
              unit: seconds

However when I try to use caffeine,

  cache:
    type: caffeine
    cache-names: rate_limit_buckets

the app starts, but the rate limiting does not work. It is even weirder that I can set cache-name to anything and the app starts. (If I do not use caffeine the app fails to start.)

I tried different ways to config caffeine (in a class, coffee-boots) but the results are the same, usually it does not work at all or it seems to ignore the caffeine config.

Thank you for your tips.

1

There are 1 answers

0
Yauheni Kuzma On

As I understand it, Bucket4j uses java.cache.CacheManager to get the cache and if we specify the cache.type=caffeine we are creating the default org.springframework.cache.CacheManager and cannot be found java.cache.CacheManager. I had a problem creating multiple caffeine caches with different specifications. I managed to solve this problem by creating multiple CacheManager in the configuration class:

  1. javax.cache.CacheManager(com.github.benmanes.caffeine.jcache.CacheManagerImpl) used to create a cache for Bucket4j:

    @Bean
    javax.cache.CacheManager cacheManagerForBucket() {
    
        CacheManagerImpl impl = new CacheManagerImpl(new CaffeineCachingProvider(), false,
            URI.create("com.github.benmanes.caffeine.jcache.spi.CaffeineCachingProvider"), 
            Thread.currentThread().getContextClassLoader(), new Properties());
        CaffeineConfiguration<Object, Object> configuration = new CaffeineConfiguration<Object, Object>();
        configuration.setExpireAfterAccess(OptionalLong.of(TimeUnit.NANOSECONDS.convert(259200, TimeUnit.SECONDS)));
        configuration.setMaximumSize(OptionalLong.of(100000l));
        impl.createCache("rate-limit-buckets", configuration);
        return impl;
    } 
    
  2. org.springframework.cache.CacheManager (org.springframework.cache.caffeine implementation.CaffeineCacheManager) for creating a caffeine caches:

    @Bean
    @Primary
    org.springframework.cache.CacheManager caffeineCacheManager() {
    
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("caffe", "caffe2");
        cacheManager.setCaffeineSpec(CaffeineSpec.parse("maximumSize=2000,expireAfterAccess=30000s"));
        return cacheManager;
    }
    
    @Bean("customCaffeine")
    org.springframework.cache.CacheManager customCaffeineCacheManager() {
    
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("cache1", "cache2");
        cacheManager.setCaffeineSpec(CaffeineSpec.parse("maximumSize=1000,expireAfterAccess=6000s"));
        return cacheManager;
    }
    

We use @Primary to give higher preference to a bean when there are multiple beans of the same type.

You also need to add an attribute with the necessary CacheManager to the @Cacheable annotation:

     @Cacheable(value ="cache1", cacheManager="customCaffeine")