In nimbus-jose-jwt, what is difference between lifespan and refreshTime? - java

The class DefaultJWKSetCache of nimbus-jose-jwt has two fields, lifespan and refreshTime.
From Java docs -
lifespan - The lifespan of the cached JWK set before it expires,
negative means no expiration.
refreshTime - The time after which the
cached JWK set is marked for refresh, negative if not specified.
Should be shorter or equal to the lifespan.
What is the difference between these two.
Does it mean that,
after the lifespan expiry the cached JWK set will be evicted and loaded again from jwks remote url (saying remote url as i am using RemoteJWKSet).
and after the refresh expiry the existing JWK set will be updated with the keys retrieved from remote url.
But i don't understand the practical difference between the two. Both seem to be doing same. Can some one explain the details with more granularity and any example.
Edit - if i give no expiry for lifespan, and 1 hour expiry for refreshTime, am i guaranteed that my keys will be updated every one hour.

The lifespan is the time after which the DefaultJWKSetCache will evict cached JWKSet. I.e., after lifespan time units passed since the cache was populated the calls to JWKSetCache.get() will always return null until new JWKSet is stored to the cache.
The refreshTime is the time that impacts value returned by JWKSetCache.requiresRefresh() method. After refreshTime time units passed since the cache was populated this method will return true, otherwise, it will return false. This setting does not impact cache behavior in any way.
The RemoteJWKSet uses the value returned by JWKSetCache.requiresRefresh() to re-download JWKSet from remote URL before the cache is actually expired. This is why documentation recommends to set refreshTime to a lesser value than lifespan.
Currently, RemoteJWKSet triggers download of remote JWKSet when either lifespan or refreshTime has passed (see this line.) Hence, there is not much difference in setting either one of these as of today. I guess some more complex logic can be potentially implemented having these two values separate.

Related

Collection Object lost due to redis TTL using redission client

We are using Redission client for java to get the data from redis but object gets deleted from collection due to TTL.
Example
We are trying the below approach to get the data from Redis with TTL.
final RList rList = client.getList(getEnvCacheKey(cacheKey));
rList.expire(7L, TimeUnit.SECONDS);
rlist.add("Value1");
rlist.add("Value2");
assertThat(rList).containsOnly("Value1", "Value2"); // This condition is true until 7 seconds
Now after 7 seconds
assert rlist.size() == 2 condition becomes false since object references are deleted due to TTL.
Due this we landed up in a production issue. Is there any way we can retain the objects even after TTL? Any sort of help will be appreciated.
The TTL(Time-To-Live) itself sets the expiration of a particular key after which the key can no longer be retrieved. If you want to keep the key in the memory you could simply skip setting rList.expire(7L, TimeUnit.SECONDS); altogether (infinite expiration).
In case you want to extend expiration, you can do so by repeating the expire command. It is also possible to remove the TTL altogether this way, although I could not tell you how to do it specifically with the Redisson.
As for the expired keys, Redis clears them 10 times a second (according to this documentation), so I don't think that you can (consistently) recover the values within the expired keys.
My general advice would be to take a step back and look at your system design. In case you are missing the expired keys, maybe this part of the product should get an extended TTL/no TTL/periodical TTL refresh

How exactly memcache removes expired data?

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.

How configure Ehcache for recalculation key instead of eviction?

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.

Guava Cache CacheLoader.refreshAfterWrite() and .expireAfterAccess() in combination

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.

How to reliably use a Guava LoadingCache when requiring persistence?

I store references in my application, e.g. (key) number => (value) name, usually for a short time (suitable to keep in memory), but sometimes for a longer time which requires me to persist it to DB (to survive application restarts and memory constraints). Earlier we always persisted to DB, but now I want to use LoadingCache as a performance enhancement as references usually are short-lived (no need to persist).
In my application I store references, e.g. key 123 => value "Paul".
I use a LoadingCache with expiry set to 45 seconds with the reasoning that if value has not been used for 45 seconds I want to persist it to DB (using a RemovalListener) so that a request for key 123 a day later from cache should return "Paul" using .load() from DB (as it's not in cache).
My question concerns that maintenance isn't guaranteed to happen immediately and that I don't understand when onRemoval()actually is called and how to solve my problem reliably.
Example flow:
1. Input is received saying that key 123 corresponds to value "Paul" which I .put() to my LoadingCache
2. Whenever data is used (often within 10-20 seconds) it's fetched via .get() and thereafter removed with .invalidate()
The LoadingCache has a RemovalListener that onRemoval() persist expired entries (checked with .wasEvicted() to avoid explicitly invalidated records) to DB table.
My problem is with how the cache's cleanup happens.
Example:
I add a value which should expire 45 seconds later.
If I try to .get() it 50 seconds later it is not returned to me as it has expired, but as I understand it from my tests there is no guarantee that value is removed using onRemoval() yet either before my .get() returns? This means I have not persisted it to DB so my load() method cannot find the value either (until later when onRemoval() actually has happened). So, I've lost my value when I need it which is not acceptable.
Am I trying to use LoadingCache for something it was not intended for or is there any way I can make it suit my needs? Or perhaps there is an alternative suggestion / solution?
Thanks a lot in advance!

Categories