How to automatically refresh Cache using Google Guava?
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()));
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, 2022Comments
-
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 almost 11 yearsCan u please give me the solution how you solved this?
-
-
Louis Wasserman almost 12 yearsFYI, bulk cache refresh operations are under discussion in Guava issue 971.
-
Adams.H over 9 yearsi 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 over 9 yearsas noted in code.google.com/p/guava-libraries/wiki/CachesExplained#Refresh 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 over 8 yearsDoes 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 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 almost 5 yearsI think you mean "CacheLoader.reload()", correct? Or has this method changed since this answer was written?
-
Frank Pavageau almost 5 years@NilsKnappmeier yes, good catch.
MyCacheLoader
is definitely not aCacheBuilder
.