RemovalListener is called not each time when an entry was evicted.
See original GitHub issueI have a RemovalListener
attached to LoadingCache
.
When the cache is accessed frequently, everything works good.
If there is no activity with the cache since entry write till entry expiration, then expired entity is “silently” evicted and removal listener is not called.
Tried with expireAfterWrite == refreshAfterWrite
and expireAfterWrite > refreshAfterWrite
.
Not sure whether it’s a bug or designed behaviour caused by combination of config params. Anyway, I cannot find the solution for the problem in the documentation.
Issue Analytics
- State:
- Created 8 years ago
- Comments:23 (12 by maintainers)
Top Results From Across the Web
Guava CacheBuilder Cache RemovalListener onRemoval ...
It doesn't get called the second time an entry is removed. (The actual removal happens. Just the onRemoval method of the removalListener doesn't ......
Read more >Inserting back into cache in RemovalListener.onRemoval
Hello, I have a use case where some of the keys in my cache needs different expireAfterWrite timeouts. So what I'm doing is...
Read more >How to use eviction, listeners, and statistics in Guava Cache
Evict the entry after the specified amount of time has passed since the entry was created or updated. TimeUnit in Java provides time...
Read more >Caffeine (caffeine 2.6.0 API) - javadoc.io
Entries are automatically evicted from the cache when any of maximumSize, ... but calling it should not be necessary with a high throughput...
Read more >CacheBuilder (Guava: Google Core Libraries for Java 22.0 API)
Entries are automatically evicted from the cache when any of maximumSize, ... but calling it should not be necessary with a high throughput...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I’m also experiencing the same issue. Forcing cleanup appears to work, however, this isn’t a desirable workaround. My entries are supposed to expire after a short period of time, but they do not. The removal listener never gets invoked and thus throws off the functionality of my application. This is of course when I do not force cleanup.
We’ve implemented active expiration for the next version of Caffeine, which provides closer to your ask of immediate expiration. The default remains to be passive and to await cache operations to trigger a maintenance cycle, which detects expired entries and removes them. That means if there is no usage of the cache then the expired entries can remain for a long period. We still consider this the appropriate default and conforms to the typical behavior of what a cache offers.
Active expiration relies on an external scheduling thread to trigger the maintenance routine based on the next expiration event. This schedules only the next to expire entry, not all entries, so it scales independent of the cache’s size. It is best effort and pacing is induced to avoid thrashing (e.g.
expireAfterAccess
resets the timestamp on each read - you don’t want nanosecond offsets causing reschedulings).In Guava/Caffeine, we take special care to ensure all of our operations are implemented in amortized O(1) worst case time, as our caches are used for tiny and humongous sizes. We also design around the semantics of a cache, which allows certain relaxations, and cases where they are not a fit deserve their own, custom solutions outside of our caches.
Java 9+ users can avoid adding their own dedicated scheduling thread by leveraging a system-wide JVM scheduler, hidden within
CompletableFuture
for itsorTimeout(duration)
option (accessed viaCompletableFuture.delayedExecutor
).This functionality works with fixed expiration policies (
expireAfterWrite
,expireAfterAccess
) and the per-entry expiration policy (expireAfter( /* per-entry custom calculation */)
). Since theScheduler
is based on when a known event fires, the scheduler does not change the semantics of other policies like reference caching. For example,weakValues()
lets the GC collect the value and the entry is eligible for eviction. However the cache is unaware, as this is done passively, and can only discover it when theReferenceQueue
is polled during the maintenance routine. We do not provide a hook to have a dedicated thread block onReferenceQueue.remove
for immediate notification. That can be easily achieved in user code via Java 9’sCleaner
, e.g.cleaner.register(value, cache::cleanUp)
in theweakValues
example.