How to automatically refresh Cache using Google Guava?

50,431

Solution 1

Guava provides no way to refresh the cache in bulk, but you can schedule a periodic refresh yourself:

LoadingCache<K, V> cache = CacheBuilder.newBuilder()
        .refreshAfterWrite(15, TimeUnit.MINUTES)
        .maximumSize(100)
        .build(new MyCacheLoader());

for (K key : cache.asMap().keySet()) {
    cache.refresh(key);
}

But in that case you may want to override the CacheLoader.reload(K, V) method in MyCacheLoader so it performs asynchronously.

As for the second question, no, you cannot set a per-entry expiration in Guava.

Solution 2

JAVA 8 version with parallel stream:

Executors
        .newSingleThreadScheduledExecutor()
        .scheduleWithFixedDelay(() -> configurationCache
                .asMap()
                .keySet()
                .parallelStream()
                .forEach((key) -> configurationCache.refresh(key)),
            0,
            1, TimeUnit.SECONDS);

Solution 3

1st question. Use a scheduled executor to kick off a periodic refresh.

2nd question. If you can infer your expiration policy from you cache key, or the previously cached value, it is possible to refresh you data at varying intervals.

based on this: https://code.google.com/p/guava-libraries/wiki/CachesExplained#Refresh

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .refreshAfterWrite(1, TimeUnit.MINUTES)
   .build(
       new CacheLoader<Key, Graph>() {
         public Graph load(Key key) { // no checked exception
           return getGraphFromDatabase(key);
         }

         public ListenableFuture<Graph> reload(final Key key, Graph prevGraph) {
           if (!needsRefresh(key,prevGraph)) {
             return Futures.immediateFuture(prevGraph);
           } else {
             // asynchronous!
             ListenableFutureTask<Graph> task = ListenableFutureTask.create(new Callable<Graph>() {
               public Graph call() {
                 return getGraphFromDatabase(key);
               }
             });
             executor.execute(task);
             return task;
           }
         }
       });

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleWithFixedDelay(
    new Runnable() {
        public void run() {
            for (Key key : graphs.asMap().keySet()) {
                graphs.refresh(key);
            }
        }
    }, 0, UPDATE_INTERVAL, TimeUnit.MINUTES);

Solution 4

Can you reload the cache value automatically using the below code snippet, without calling the refresh method ??

cacher =
        CacheBuilder.newBuilder()
            .refreshAfterWrite(10, TimeUnit.SECONDS)
          .build(CacheLoader.asyncReloading(new CacheLoader<String, String>() {

              @Override
              public String load(String key) throws Exception {
                return method-call();
              }
            }, Executors.newSingleThreadExecutor()));
Share:
50,431
K. Siva Prasad Reddy
Author by

K. Siva Prasad Reddy

I am a software developer with 11+ years of experience in building enterprise applications on JVM platform. I am a blogger, book author and has passion for learning new technologies.

Updated on July 09, 2022

Comments

  • K. Siva Prasad Reddy
    K. Siva Prasad Reddy almost 2 years

    I am using Google Guava library for caching. For automatic cache refresh we can do as follows:

    cache = CacheBuilder.newBuilder()               
                        .refreshAfterWrite(15, TimeUnit.MINUTES)
                        .maximumSize(100)
                        .build(....);
    

    However, automatic refreshes are performed when the first stale request for an entry occurs.

    Is there a way to refresh it automatically even though no requests came for cache data? Like for every 15 minutes the cache data should be pulled from Db and load it, no matter whether anybody called cache data or not.

    Also, Guava's cache expiry time is for entire cache. Is it possible to expire cache values based on key? Like cache data with key "NOT_SO_FREQ_CHANGE_DATA" to expire for every 1 hour and data with key "FREQ_CHANGING_DATA" should expire for every 15 minutes?

    • leostiw
      leostiw almost 11 years
      Can u please give me the solution how you solved this?
  • Louis Wasserman
    Louis Wasserman almost 12 years
    FYI, bulk cache refresh operations are under discussion in Guava issue 971.
  • Adams.H
    Adams.H over 9 years
    i looked in the reload method, when needsRefresh(key) is true , it will go to else statement , then it will go to execute the task , but i don't see it return the old value . i was thinking it should return the old value first and go for the new value asychronously .
  • McKidoubled
    McKidoubled over 9 years
    as noted in code.google.com/p/guava-libraries/wiki/CachesExplained#Refre‌​sh the guava cache reload inherently does return the old value, while refreshing the cache asynchronously. Refreshing is not quite the same as eviction. As specified in LoadingCache.refresh(K), refreshing a key loads a new value for the key, possibly asynchronously. The old value (if any) is still returned while the key is being refreshed, in contrast to eviction, which forces retrievals to wait until the value is loaded anew.
  • gar
    gar over 8 years
    Does this code address the questions from the OP's question? If so, could you expand on how the cache is refreshed without data being requested and is it possible to expire cache values based on key.
  • Johan Sjöberg
    Johan Sjöberg over 6 years
    "In contrast to expireAfterWrite, refreshAfterWrite will make a key eligible for refresh after the specified duration, but a refresh will only be actually initiated when the entry is queried." Quote from github.com/google/guava/wiki/CachesExplained
  • Nils Knappmeier
    Nils Knappmeier almost 5 years
    I think you mean "CacheLoader.reload()", correct? Or has this method changed since this answer was written?
  • Frank Pavageau
    Frank Pavageau almost 5 years
    @NilsKnappmeier yes, good catch. MyCacheLoader is definitely not a CacheBuilder.