My Use case: I have to return the updated data from the cache every time without hitting the DB. So i have used RefreshAhead feature of Cache2K.
Issue: I am facing few issues.
I have kept expiry interval as 1 Minute, eternal = false and keepDataAfterExpired = TRUE. But after 1 Minute when I am trying to get the expired content, it’s not getting served from the cache due to which spikes are coming in response time. Is there anyway to serve the expired cache content to avoid these spikes.
I have used the loader but unable to find any parameter to set the loader execution interval. Do we have any property to set the loader execution interval. If not then what would happen if our DB call took more time and expiry interval get elapsed as expired content is not getting served from Cache.
Please suggest which loader I have to use to load the findAll() data into the cache. It would be helpful if an example would be share for reference.
Any logger provided by default to reflect that cache is refreshed successfully.
Code Snippet:
this.itemsCache = new Cache2kBuilder<String, List>(){}.name("allItems").keyType(String.class).valueType(List.class) .eternal(false) .expireAfterWrite(60, TimeUnit.SECONDS).setupWith(UniversalResiliencePolicy::enable, b-> b.resilienceDuration(2, TimeUnit.SECONDS)) .keepDataAfterExpired(true).refreshAhead(true).boostConcurrency(true).disableStatistics(false).disableMonitoring(false).recordModificationTime(true) .addAsyncListener(new CacheEntryCreatedListener<String,List>() { @Override public void onEntryCreated(Cache cache, CacheEntry cacheEntry) throws Exception { logger.info("Cached entry created: "+cacheEntry.toString()); } }).addAsyncListener(new CacheEntryExpiredListener<String,List>() { @Override public void onEntryExpired(Cache cache, CacheEntry cacheEntry) throws Exception { logger.info("Cached entry expired: "+cacheEntry.toString()); } }).addAsyncListener(new CacheEntryUpdatedListener<String,List>() { @Override public void onEntryUpdated(Cache cache, CacheEntry cacheEntry, CacheEntry cacheEntry1) throws Exception { logger.info("Cache entry updated from: "+cacheEntry.toString()+", to: "+cacheEntry1.toString()); } }).loader(key->{ logger.info("Cache repopulating by loader for key: "+key); List<Item> iList = populateStrings(); logger.info("Loader Updated Items List: "+iList.toString()); return iList; }).permitNullValues(false).disableMonitoring(false).disableStatistics(false).recordModificationTime(true).build();
Advertisement
Answer
With refreshAhead(true)
it should work as you intend. The documentation reads as:
When
true
, enable background refresh / refresh ahead. After the expiry time of a value is reached, the loader is invoked to fetch a fresh value. The old value will be returned by the cache, although it is expired, and will be replaced by the new value, once the loader is finished. In the case there are not enough loader threads available, the value will expire immediately and the nextget()
request will trigger the load.. . .
Maybe you are having problems because not enough threads are available to call the loader? You can adjust the threads via loaderThreadCount
or by specifying an executor in loaderExecutor
.
keepDataAfterExpired
does not change anything here. It is only useful together with an AdvancedCacheLoader
or and AsyncCacheLoader
.
For the next version of cache2k (2.8) I am planing to improve the refresh ahead configuration options. Then it will be possible to refresh before the expiry.