Update (tl;dr)
Single entries shall be evicted from Cache after their TTL is due.
Setup:
- Java: 17
- spring-boot.version: 3.0.x
Objective
Requests providing an ID (each) are asking for data. The data is stored in a repository - we can assume any kind of a KV-Store alike <fooId, fooData>. To speed up the repositorie's answer, the repository is wrapped by a SpringBoot-Cache.
Approach for fast answers:
- Ask the cache first
- Ask the Repository, if the cache could not provide an answer.
For the cache to stay small the entries shall be evicted.
Samples and guides like ( https://www.baeldung.com/spring-cache-tutorial ) hand suitable code for eviction ...
... BUT the entries in the Cache shall not be evicted alltogether. Each entry shall exist in the Cache for (e.g.) 30 minutes after the last request.
Sample event flow:
To say it using events:
a) Entry foo1 is requested
- foo1 will be evicted in 30 minutes from now (-> 30)
.. 10 minuts pass (Sum: 10 min)
b) Entry foo2 is requested
- foo2 will be evicted in 30 minutes from now (-> 40)
.. 10 minuts pass (Sum: 20 min)
c) Entry foo1 is requested (again)
- foo1 is reset to be evicted in 30 minutes from now (-> 50)
.. 10 minuts pass (Sum: 30 min)
- nothing happens
- foo1 has 20 Minutes remaining until TTL is due
- foo2 has 20 Minutes remaining until TTL is due
.. 10 minuts pass (Sum: 40 min)
d) Entry foo2 is evicted as TTL is expired
- foo1 has 10 Minutes remaining until TTL is due
.. 10 minuts pass (Sum: 50 min)
e) Entry foo1 is evicted as TTL is expired
Is there an easy way to solve this issue without using external libraries/products?
Sample external libraries/products not to use:
- EhCache
- Gemfire
- Guava
Thanks for any advice :)
Research approaches ... .. .
(i) Is there an Implementation from SpringBoot itself?
From ..
.. I could extract as of 2020:
--> Sadly: NOT to the recent knowledge ... :-/
(ii) Evict everything
Of couse this is not desirable in the first place, but the cache could be evicted completely to be refilled
Downside:
(iii) Wrap the Cache
If the entries in the Cache are 'big'/'huge', a reasonable approach would be to setup another hashmap fooTTL, which stores <ID, TTL>-pairs.
Then a fixed delayed/scheduled function loops the fooTTL and evicts due entries from the cache.
Downside:
(iv) Reevaluate the use of external libraries/products
Maybe the as the use of external libraries/products offers a better set of functions or a less cumbersome implementation.
Downside:
(v) Replace the Cache
In the first place the
SpringBoot Simple Cacheis a "Key-Value"-Pair HashMap<K,V>. Maybe it is even a ConcurentHashMap<K,V>.Anyways, a handcrafted class using a ConcurentHashMap<K,V> might be your solution, as everything stays in memory.
The functions from the
SpringBoot Simple Cacheare pretty simple.This interface could be extended by:
The key stays equivalent to the implementation given by Spring. Additionally the new value field wrappes two fields:
SpringBoot Simple CacheFinally the
deleteByTtl-funtion can be@Sceduledto iterate over all entries evicting only those with an expired ttl.Downside:
Still approach (v) remains straight foreward regarding the persued functionality.