Intro
This is regarding infinispan cache but I think this is a generic enough question.
In my infinispan cache Im inputting items into cache using putIfAbsent method and removing them with remove method. (jboss doc here)
Basic Behavior
I can put items into my cache and remove items from cache using a id. But if I do not remove the cache item explicitly, infinispan will remove it automatically after the specified life span is passed.
In my remove method I run some custom code before removal.
But when I am not invoking the remove method, infinispan remove the cache entry due to the expiry of provided life span.
In that automatic removal scenario I cannot run my custom code because it happens under the hood. (by infinispan). So what is the possible way? Following code will explain this a bit more hopefully.
I belive I am clear enough. Please give me some insight.
Thank you.
void putToCache(String id){
myCache.putIfAbsent(id,value,LIFESPAN_DURATION,timeUnit);
}
void removeFromCache(String id){
//MY CUSTOM CODE - WANT TO RUN THIS IN LIFE SPAN DURATION EXPIRY ALSO
myCache.remove(id);
}
Before going into the answer I want to clarify between eviction and expiration.
Eviction
Eviction is when an entry is removed from the in memory container due to it growing outside of the configured maximum size (max-entries). Eviction can only be enabled at configuration time and is not controlled at runtime which Expiration can be, please see here. Note that eviction never removes an entry from a store if you have one configured, thus you don't just lose an entry due to having too many if you don't want to.
Infinispan 7 and older versions have a listener for Eviction as you already found, and the event raised would be this one.
Expiration
Expiration defines an entry being removed after a period of inactivity or a set duration. This can be configured through configuration or you can override the configured value by using the API as you did your in example.
Now to answer your question, an Infinispan Expiration event was added with Infinispan 8. It is detailed more here. Note an important piece is that the expiration event will be fired holding the lock for the key that is expiring (unless your listener is defined as async). This is important to guarantee proper ordering.
Also you should keep in mind that expiration events are not guaranteed to fire exactly when the entry expires. Rather the event is only fired upon accessing said expired entry or if the expiration reaper thread finds the expired entry. The expiration reaper defaults to run every minute, you can disable this or change the time by changing the expiration interval configuration setting.
Related
I am using com.google.appengine.api.memcache.MemcacheService to work with Google Memcache.
When storing a value, I set an expiration of 60 seconds. But the value is still returned from the cache even after several minutes.
The code for working with Memcache:
// Config
int expirationSeconds = 60;
Expiration expiration = Expiration.byDeltaSeconds(expirationSeconds);
MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
// Write operation
memcache.put(id, value, expiration);
// Read operation
memcache.get(id);
I am expecting the value to be absent in this case because the Memcache documentation says that An expired item is removed when someone unsuccessfully tries to retrieve it.
Why the expired value is still returned from Memcache?
The documentation uses two words evicted and removed that could be understood to be interchangeable but they aren't:
By default, all values remain in the cache as long as possible, until evicted due to memory pressure, removed explicitly by the app, or made unavailable for another reason (such as an outage).
And in the note here we can see how removal process works:
The actual removal of expired cache data is handled lazily. An expired item is removed when someone unsuccessfully tries to retrieve it.
At the same place the eviction is explained like that:
The value is evicted no later than this time, though it can be evicted earlier for other reasons. Increment the value stored for an existing key does not update its expiration time.
Eviction is something akin to soft removal where the value is unavailable but is still in the Memcache. Removal does the actual removal.
Let say that object in the cache need to be evicted. But instead of eviction a new value should be calculated and put in the cache. It is important that until old value should be used until new value is generated to guarantee that there is no lock. Can Ehcache be configured for such behavior?
Let say that object in the cache need to be evicted.
A cache entry could be evicted due to capacity limits and because the cache entry wasn't requested (hit) recently. Resources need to be freed, nothing about the entry is known any more. When the respective key is requested again, the value needs to be computed again and you cannot hide the additional latency.
A cache entry could expire, e.g. because there is a time to live time span configured. Expiry can happen, while there are lots of incoming requests for that entry. Of course, in this case you may not want that the entry gets removed from the cache, you just want that the value to be refreshed.
Refreshing a value automatically when it expired is called refresh ahead or background refresh. The answer about that is here: Refreshing Caches while under load with Spring/EHCache
I am not sure what you mean by "needs to be evicted". The normal Ehcache flow would be the following:
Set an entry in the cache
Things getting this entry
The entry is now obsolete so the application set the new value
Things getting this entry (with the new value)
There is no locking involved. Anything getting the entry will directly get the old or the new value without waiting. Unless you are using a loader.
My use-case is that I need to implement a cache on top of a service should expire entries after a certain amount of time (from their time of creation).
And if the entry is getting expired, then service look up should be done to get the latest entry. lets call is service refresh.
But, lets say if service refresh fails, then I should be able to use the stale data in the cache.
But since the cache is already expired, I don't have that entry.
So, I am thinking of controlling the expiration of the cache and cache entry would only be expired only if service is available to get the latest data, otherwise don't remove that entry.
I was looking into Google Guava cache, but it only provides a removalListener which would just notify me with the event but I am not able to control the expiration event with this.
Is there any third party cache implementation which can serve my purpose?
This kind of resilience and robustness semantics are implemented in cache2k. We use this in production for quite some time. The setup looks like
CacheBuilder.newCache(Key.class, Value.class)
.name("myCache")
.source(new YourSourceImplementation())
.backgroundRefresh(true)
.suppressExceptions(true)
.expiryDuration(60, TimeUnit.SECONDS)
.build();
With exceptionExpiryDuration you can actually set a shorter interval for the retry. There was a similar question on SO, which I also answered, see: Is it possible to configure Guava Cache (or other library) behaviour to be: If time to reload, return previous entry, reload in background (see specs) There you find some more details about it.
Regardless what cache you use, you will run into a lot of issues, since exception handling in general and building robust and resilient applications needs some thoughts in the details.
That said, I am not totally happy with the solution yet, since I think we need more control, e.g. how long stale data should be served. Furthermore, the cache needs to have some alerting if there is stale data in it. I put some thoughts on how to improve this here: https://github.com/cache2k/cache2k/issues/26
Feedback is very welcome.
We are using a Guava LoadingCache which is build by a CacheLoader.
What we are looking for, is a Cache which will refresh its content regularly, but also expires keys after a given (longer) timeframe, if the key is not accessed anymore.
Is it possible to use .refresAfterWrite(30, TimeUnit.SECONDS) and also .expireAfterAccess(10,TimeUnit.MINUTES) on the same CacheLoader?
My experience is that the keys are never evicted because of the regular reload through refreshAfterWrite. The documentation leaves me a little uncertain about this point.
This should behave as you desired. From the CacheBuilder docs:
Currently automatic refreshes are performed when the first stale request for an entry occurs. The request triggering refresh will make a blocking call to CacheLoader.reload(K, V) and immediately return the new value if the returned future is complete, and the old value otherwise.
So if a key is queried 30 seconds after its last write, it will be refreshed; if it is not queried for 10 minutes after its last access, it will become eligible for expiration without being refreshed in the meantime.
When using ehcache, is there a way to expire cache on certain time of the day?
Thanks,
Lawardy
There is no such functionality out-of-the-box. You need an external solution like Quartz, also from Terracotta umbrella.
In fact, even normal timeToLive parameter does not remove element in question after this time elapses, because this would required additional thread. Instead the item is removed when new one is to be added which takes its place.