Ven
Ven

Reputation: 1

Is there a Caffeine feature that will purge a particular item from the cache after defined time and recreates it at the same time?

ExpireAfter will only purge the item but will not re-create the item. So what I need to do is, after a predefined interval, I need to purge a particular item from the cache and at the same time I need to recreate it. It might recreate with same data if there is no change in the data. Assuming the data was changed, the recreating will give the latest object.

My idea was to retrieve latest item form the cache all the time. In contrast, the Refresh feature (https://github.com/ben-manes/caffeine/wiki/Refresh) will provide the stale item for the first request and does an asynchronous loading. So for the second request the cache will provide the latest object.

Assuming cache can address the following two cases:

Subsequent requests case:

In the case where the cache has to load values equal to its capacity at one shot:

Upvotes: 0

Views: 1688

Answers (1)

Ben Manes
Ben Manes

Reputation: 9621

Asynchronous removal listener that re-fetches the expired entry should work in my case. Can you please provide me some information on how to achieve this?

The removal listener requires a reference to the cache, but that is not available during construction. If it calls a private method instead then the uninitialized field isn't captured and it can be resolved at runtime.

Cache<K, V> cache = Caffeine.newBuilder()
    .expireAfterWrite(1, TimeUnit.HOURS)
    .removalListener((K key, V value, RemovalCause cause) -> {
      if (cause == RemovalCause.EXPIRED) {
        reload(key);
      }
    }).build();

private void reload(K key) {
  cache.get(key, k -> /* load */);
}

I'm also curious to know how the scheduled task can do it?

If you are reloading all entries then you might not even need a key-value cache. In that case the simplest approach would be to reload an immutable map.

volatile ImmutableMap<K, V> data = load();

scheduledExecutorService.scheduleAtFixedRate(() -> data = load(), 
    /* initial */ 1, /* period */ 1, TimeUnit.HOURS);

I understand the refreshAfterWrite will provide the stale entry for the first time but for the second request, what happens if the cache hasn't yet completed loading the expired entry?

The subsequent requests obtain the stale entry until either (a) the refresh completes and updates the mappings or (b) the entry was removed and the caller must reload. The case of (b) can occur if the entry expired while the refresh was in progress, where returning the stale value is no longer an option.

Does cache blocks the second request, completes the re-fetch, and then provide the latest value to the second request?.

No, the stale but valid value is returned. This is to let the refresh hide the latency of reloading a popular entry. For example an application configuration that is used by all requests would block when expired, causing periodic delays. The refresh would be triggered early, reload, and the callers would never observe it absent. This hides latencies, while also allowing idle entries to expire and fade away.

In the case where the cache has to load values equal to its capacity at one shot... after the defined expiry time, the cache should evict and re-fetch all the 100 elements.

The unclear part of your description is if the cache reloads only the entries being accessed within the refresh period or if it reloads the entire contents. The former is what Caffeine offers, while the latter is better served with an explicit scheduling thread.

Upvotes: 0

Related Questions