Make Ehcache return expired data if LoaderWriter fails - ehcache

Is it possible to set up Ehcache in such a way that cache will return "expired" data if the underlying CacheLoaderWriter fails (throws an Exception)?
Accordingly to my tests, if a given cache entry is expired, and CacheLoaderWriter fails to load data, cache returns null.
However, on my case, it would be better to return the expired cached data than nothing. What I am doing as a work around is to store the latest successfully loaded data in the CacheLoaderWriter, so if a new execution of the load fails, I return this copy. Anyway, think that would be more "memory efficient" to, somehow, return the data that it's already in the cache, instead of keeping another copy in the CacheLoaderWriter.
I am using ehcache 3.4.0
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("myCacheName",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class, ResourcePoolsBuilder.heap(100))
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(4, TimeUnit.HOURS)))
.withLoaderWriter(new TestCacheLoaderWriter()))
.build();

It is not possible. However, unless you are using a copier, it isn't a copy you are keeping in your loader-writer. It's only another reference to the object in cache.
Your request could be filed as an enhancement in the Ehcache issue tracker.
The alternative would be to never expire the data but replacing it from outside when needed.

Related

Spring Cache Hit Flag/Indicator

I am using Spring Cache to cache some objects through #Cacheable. However, 1 of the requirement requires me to be able to know if the returned object was from the Cache Hit or standard call. Is there any flag or indicator thats gets set i can use to check this ?
I have seen past questions regarding cache hits being logged whenever there are cache hits but that is not really useful for my situation. I am currently using Spring Cache with the Simple Provider and am open to using any external Cache Managers that is able to do this.
Yes, we can know whether it is a cache hit or a cache miss(a direct call to REST call or a database call) using a flag.
Using #Cacheable, it always first checks in the cache, before it executes the method, if found in cache, it will skip the method execution, where as #CachePut works slightly different, where it will executes the adivised method & updates the cache, so it will miss the cache always.
For example:
private volatile boolean cacheMiss = false;
public boolean isCacheMiss(){
boolean cacheMiss = this.cacheMiss;
this.cacheMiss = false; //resetting for next read
return cacheMiss;
}
protected void setCacheMiss(){
this.cacheMiss = true;
}
#Cacheable("Quotes")
public Quote requestQuote(Long id) {
setCacheMiss();
//REST CALL HERE
return requestQuote(ID_BASED_QUOTE_SERVICE_URL,
Collections.singletonMap("id", id));
}
cacheMiss variable gives the status, whether it is from cache or not.
Here is it discussed Spring Caching with GemFire, the underlying caching provider is Pivotal GemFire. You can use any such caching providers.

Spring Boot #Cachable - how to find out expire datetime at runtime?

When using #Cachable in Spring, is there any way to find out at runtime if the next method call would be a cache hit or cache miss? Or, at what datetime the cache expires?
The background is, it would be nice to have a scheduled job which refreshes caches just before they expire. Also, this could allow us to find out if caches are expired and show the user a message that the system is now refreshing the caches. "please hold on, we are refreshing your caches for XY" to let the user know what's going on. - Please note we use the Cacheable feature to cache method calls which collect data from multiple calls to a 3rd party system which take up to several minutes.
There is no such thing in the Spring Cache abstraction.
As the data collection takes minutes, and the users might need that last value while data is being collected, you can't wait for the cache eviction to collect new data.
One solution would be to add an #Scheduled task that populates the cache calling a method with the #CachePut.
CachedService.java
#CachePut(cacheNames="book", key="#isbn")
public Book updateBook(int id, Book book) {
// Left blank
}
Config.java
#Scheduled(fixedRate = 60000)
public void reportCurrentTime() {
log.info("refreshing cache");
... long data collection ...
// Call method that has #CachePut
service.updateBook(bookId, book);
log.info("cache refreshed");
}
The example shows 60000ms (1 minute), it updates the cache every minute. You have to calculate it so it is less time than the Spring Cache expiration time. i.e. (expire time - request time)

Ehcache calling loadAll cacheloaderwriter with single item iterable

I am using Ehcache 3.1.1 on heap store.
cache = cacheManager.createCache(name,
CacheConfigurationBuilder.newCacheConfigurationBuilder(key, value, ResourcePoolsBuilder.heap(entries))
.withLoaderWriter(loader)
.build()
);
I have a CacheLoaderWriter which supports loadAll.
When making calls to getAll on the cache, misses route through to the loader, but call loadAll multiple times with single item iterators.
I believe this may be an issue in OnHeapStore bulkComputeIfAbsent
Please advise if I am missing a configuration to enable batching via loadAll.
I was unable to find this reported as a bug.
EDIT: I don't feel like I explained it well originally. So getAll is called with a key set size of 2, loadAll is called twice in that situation with the keyset being size of 1 each time.
You did nothing wrong in your configuration - please open an issue against Ehcache3

EhCache - remove expired element (because of timeToIdleSeconds or timeToLiveSeconds) without try to get it?

The EhCache documentation says:
Accessing an entry in myCache that has been idle for more than an hour (timeToIdleSeconds) causes that element to be evicted.
If an entry expires but is not accessed, and no resource constraints force eviction, then the expired entry remains in place.
getting an expired element will remove it from the cache and return null.
If you implement and register a CacheEventListener to receive that an element is expired, you can see the event is fired when you try to get an expired element, but not after the 'timeToIdleSeconds'.
Is it possible to force removing the expired element after it is expired?
Because in my case after this time no one will try to get it again.
Thank you.
I've done it with the following code:
cache.evictExpiredElements();
cache.flush();
In Version 3 of EhCache and up you cant use cache.evictExpiredElements() anymore and most likely you shouldn't :)
But if you have to, here is my solution:
final Iterator<Entry<String, Bean>> iterator = cache.iterator();
while (iterator.hasNext()) {
iterator.next();
}
This will force the cache to get every element in it, return null for expired elements and remove them. In addition I created an CacheEventListener to catch the eviction event to do some stuff.
As mentioned before, analyze your usecase carefully and make sure that there is no better way than brute force.

Cache invalidation in Ehcache

I am using Ehcache in Hibernate.
How can I notify the cache that the database has changed? How can I invalidate the cached data? How can I programmatically achieve this?
What do exactly mean? There are 2 ways to make a change in the database: inside the app & outside the app
Inside the app you can trigger easily an invalidation. The second one is a harder to solve. Cache elements are stored with a key and based on that key you can delete it.
CacheManager manager = CacheManager.getInstance();
cache = manager.getCache(cacheName);
cache.remove(key);
or
cache.removeAll();
Depending how you configured ehcache of course. But you need to know the name of the cache that holds the object.
This is how you can invalidate all EhCache items without bothering what the individual cache names are:
CacheManager manager = CacheManager.getInstance();
String[] names = manager.getCacheNames();
for (String name : names)
{
Cache cache = manager.getCache(name);
cache.removeAll();
}
Try:
CacheManager.create().clearAll()
It will clear all caches in CacheManager.
To clear only one particular cache, get it from cache manager and remove all elements:
CacheManager cacheManager = CacheManager.create();
Ehcache cache = cacheManager.getEhcache(cacheConfiguration.getName());
cache.removeAll();
Set cache expiration so data is refreshed as or more often than the database changes .
Also you can update in cache only elements that change in the database .
In case if you want to remove a specific cache (eg:employeeCache)
#Autowired
CacheManager cacheManager;
place where you want to invalidate cache, use below code
Cache cache = cacheManager.getCache("employeeCache");
cache.removeAll();

Resources