Open TonyWeston opened 1 year ago
/cc @gwenneg (cache)
I'm not sure this will be possible with Caffeine (the default implementation) but you can invalidate the entry manually as a workaround, i.e. something like:
@Inject
Vertx vertx;
@CacheName("my-cache")
Cache cache;
@Inject
FooService service;
Uni<Foo> getFoo() {
return cache.getAsync("foo", key -> {
return service.findFoo().invoke(foo -> vertx.setTimer(foo.getExpiryTime(), () -> cache.invalidate("foo").await().indefinitely()));
});
}
Alternatively, you can inject the default ScheduledExecutorService
and use the schedule()
method instead of Vertx#setTimer()
.
This is from the caffeine github, for interface com.github.benmanes.caffeine.cache.Policy - expireVariably appears to fit the use case of having per-entry expiration times.. ?
one thing the caffeine api allow is to set an expiration policy based on the payload.
package com.github.benmanes.caffeine.cache;
public interface Expiry<K, V> {
/**
* Specifies that the entry should be automatically removed from the cache once the duration has
* elapsed after the entry's creation. To indicate no expiration an entry may be given an
* excessively long period, such as {@code Long#MAX_VALUE}.
* <p>
* <b>Note:</b> The {@code currentTime} is supplied by the configured {@link Ticker} and by
* default does not relate to system or wall-clock time. When calculating the duration based on a
* time stamp, the current time should be obtained independently.
*
* @param key the key represented by this entry
* @param value the value represented by this entry
* @param currentTime the current time, in nanoseconds
* @return the length of time before the entry expires, in nanoseconds
*/
long expireAfterCreate(K key, V value, long currentTime);
/**
* Specifies that the entry should be automatically removed from the cache once the duration has
* elapsed after the replacement of its value. To indicate no expiration an entry may be given an
* excessively long period, such as {@code Long#MAX_VALUE}. The {@code currentDuration} may be
* returned to not modify the expiration time.
* <p>
* <b>Note:</b> The {@code currentTime} is supplied by the configured {@link Ticker} and by
* default does not relate to system or wall-clock time. When calculating the duration based on a
* time stamp, the current time should be obtained independently.
*
* @param key the key represented by this entry
* @param value the value represented by this entry
* @param currentTime the current time, in nanoseconds
* @param currentDuration the current duration, in nanoseconds
* @return the length of time before the entry expires, in nanoseconds
*/
long expireAfterUpdate(K key, V value, long currentTime, @NonNegative long currentDuration);
/**
* Specifies that the entry should be automatically removed from the cache once the duration has
* elapsed after its last read. To indicate no expiration an entry may be given an excessively
* long period, such as {@code Long#MAX_VALUE}. The {@code currentDuration} may be returned to not
* modify the expiration time.
* <p>
* <b>Note:</b> The {@code currentTime} is supplied by the configured {@link Ticker} and by
* default does not relate to system or wall-clock time. When calculating the duration based on a
* time stamp, the current time should be obtained independently.
*
* @param key the key represented by this entry
* @param value the value represented by this entry
* @param currentTime the current time, in nanoseconds
* @param currentDuration the current duration, in nanoseconds
* @return the length of time before the entry expires, in nanoseconds
*/
long expireAfterRead(K key, V value, long currentTime, @NonNegative long currentDuration);
}
We could imagine a similar API for the quarkus cache. This way depending of the backend we could either set a cache wide policy (suitable for caffeine) or leverage the policy to compute the expiration before updating an item and send it to the backend.
also I am thinking, it is possible to wrap objects in caffeine using a POJO similar to
public class CaffeineWrapper<T> {
long expiration;
T data;
}
then using a custom Expiry we could set the expiration based on the CaffeineWrapper.expiration, since we have access to the payload.
not sure if the best way to go is
<K, V> Uni<V> get(K key, Function<K, V> valueLoader);
<K, V> Uni<V> get(K key, Function<K, V> valueLoader, Duration expiresIn);
https://github.com/rmanibus/quarkus/commit/aa102ed837847b3430a53c0c7fec058144c135b5
or
<K, V> Uni<V> get(K key, Function<K, CacheValue<V>> valueLoader);
This second approach seems preferable since the expiration is computed only if the cache is set, however its introducing a breaking change
https://github.com/rmanibus/quarkus/commit/8a4bfc77d4575e110a022954a61a707b918754f8
Description
Currently, quarkus caching only invalidates entries based on a fixed time since they were added, or accessed. Provide an additional API that can specify when an entry is to be expired. This would be useful, for example, for when caching a resource fetched using the JaxRS client, based on the Cache-control header.
Implementation ideas
If the cache is accessed directly, there is the method:
This could be enhanced by returning a wrapped value, where needed: