Caffeine cache refresh / reload cache manually or on demand
Asked Answered
P

1

8

I have implemented caffeine cache in my application. I am caching data from few static tables. But i want to know if i can refresh / clear / reload cache manually or on demand using a REST API or any other way. Can any one please suggest a way to implement such a requirement.

I want something like :- an endpoint url like :- http://localhost:8080/refreshCache

this will trigger some method internally and clear the cache or reload new values in cache manually.

Below is the cache configuration:

@Configuration
public class CacheConfig{

     private com.github.benmanes.caffeine.cache.Cache<Object, Object> cache;

    @Bean
    Caffeine<Object,Object> cacheBuilder(){
        return Caffeine.newBuilder()
                .initialCapacity(300)
                .maximumSize(50000)
                .expireAfterAccess(1, TimeUnit.DAYS)
                .removalListener(new CacheRemovalListener())
                .recordStats();
    }

    class CacheRemovalListener implements RemovalListener<Object, Object> {
        @Override
        public void onRemoval(Object key, Object value, RemovalCause cause) {
            System.out.format("Removal listener called with key [%s], cause[%s], evicted [%s] %n", 
                    key , cause.toString(), cause.wasEvicted());
        }
    }

} 
Pronghorn answered 1/3, 2018 at 13:43 Comment(11)
If you have the cache instance then you can call invalidateAll() to clear it. If you are using Spring Cache, you’ll need it check its documentation for a clear functionality.Tomsk
Hi Ben can you tell me, which cache instance should be used ? What should be the modification in above implementation ?Pronghorn
I only see the builder, not the construction. I don’t use Spring and it seems like your questions are more about it than Caffeine. If so, perhaps ask in the Spring forum.Tomsk
On top of method i have just used @Cacheable("some_listname") annotation. Apart from that nothing has been usedPronghorn
I think you want @CacheEvict(allEntries=true) according to the docsTomsk
Also i want to check what values/elements are there in the cache or what all elements have been cached. How can i check the cached valuesPronghorn
You could inspect using the asMap() viewTomsk
@Ben: Can you please provide some code for it ? I tried but it was throwing me exception when i was trying the samePronghorn
System.out.println(cache.asMap()) should be enough to debug for startersTomsk
I can use this cache.asMap () but lets say i have configured cache in some cacheConfig.java file and i want to get the values stored in the cache in some cacheUtility.java file in that case how will i get this cache there in the utility file. Also, considering i have n number of caches configured for my application based on specific names i.e. each cache have a separate name. In that scenario lets say i want cached data for cache named xyzCache then how will i get cached data for only that xyzCache ?Pronghorn
Spring has a global CacheManager where each of the cache instances are stored, as a global registry. I think you could fetch the cache through that, right?Tomsk
P
8

You can use Spring's CacheManager to create CaffeineCache instances and then you can perform CRUD operations on any cache using CacheManager.

See Below code.

Bean Configuration:

public class CacheBeansConfig {

  @Bean
  public CacheManager cacheManager() {
    // create multiple instances of cache
    CaffeineCacheManager cacheManager = new CaffeineCacheManager("UserCache","InventoryCache");
    cacheManager.setCaffeine(caffeineCacheBuilder());
    return cacheManager;
  }

  private Caffeine<Object, Object> caffeineCacheBuilder() {

    return Caffeine.newBuilder()
        .initialCapacity(<initial capacity>)
        .maximumSize(<max size>)
        .expireAfterAccess(<expire after hrs>, TimeUnit.HOURS)
        .recordStats();
  }

This will initialize your CacheManager with two Caffeeine Cache instances.

Use below Rest Controller Class to access these class.

@RestController
@RequestMapping(path = "/v1/admin/cache")
public class ACSCacheAdminController {

  @Autowired
  private CacheManager cacheManager;

  /**
   * call this to invalidate all cache instances
   */
  @DeleteMapping(
      path = "/",
      produces = {"application/json"})
  public void invalidateAll() {
    Collection<String> cacheNames = cacheManager.getCacheNames();
    cacheNames.forEach(this::getCacheAndClear);
  }

  /**
   * call this to invalidate a given cache name
   */
  @DeleteMapping(
      path = "/{cacheName}",
      produces = {"application/json"})
  public void invalidateCache(@PathVariable("cacheName") final String cacheName) {
    getCacheAndClear(cacheName);
  }

  /**
   * Use this to refresh a cache instance
   */
  @PostMapping(
      path = "/{cacheName}",
      produces = {"application/json"})
  public void invalidateCache(@PathVariable("cacheName") final String cacheName) {
    getCacheAndClear(cacheName);
    Cache cache = cacheManager.getCache(cacheName);
    // your logic to put in above cache instance
    // use cache.put(key,value)
  }


  /**
   * call this to invalidate cache entry by given cache name and cache key
   */
  @DeleteMapping(
      path = "/{cacheName}/{key}/",
      produces = {"application/json"})
  public void invalidateCacheKey(
      @PathVariable("cacheName") final String cacheName, @PathVariable("key") Object key) {
    final Cache cache = cacheManager.getCache(cacheName);
    if (cache == null) {
      throw new IllegalArgumentException("invalid cache name for key invalidation: " + cacheName);
    }
    cache.evict(key);
  }

  @GetMapping(
      path = "/{cacheName}/{key}",
      produces = {"application/json"})
  public ResponseEntity<Object> getByCacheNameAndKey(
      @PathVariable("cacheName") final String cacheName, @PathVariable("key") final int key) {
    final Cache cache = cacheManager.getCache(cacheName);
    if (cache == null) {
      throw new IllegalArgumentException("invalid cache name: " + cacheName);
    }
    return ResponseEntity.ok().body(cache.get(key));
  }

  private void getCacheAndClear(final String cacheName) {

    final Cache cache = cacheManager.getCache(cacheName);
    if (cache == null) {
      throw new IllegalArgumentException("invalid cache name: " + cacheName);
    }
    cache.clear();
  }

Just change the code as per your need :)

Placia answered 8/9, 2019 at 7:15 Comment(1)
This is exactly what I want to do but I can't get the configuration to work because org.springframework.cache.caffeine.CaffeineCacheManager doesn't exist in my Spring version (4.3.10). Is that a Spring Boot-only package, or am I missing a dependency? I do have Caffeine in my deps and its packages are available. thxGregarine

© 2022 - 2024 — McMap. All rights reserved.