Caffeine Cache supports Asynchronous loading, but what does this look like for WebFlux’s Mono
s?
An example without Mono
s can be found on the official wiki: https://github.com/ben-manes/caffeine/wiki/Population
Given that we have a call like this to cache:
Mono<Something> uncachedCall(ExampleKey key) { ... }
Then we need a wrapper type and function (Caffeine cache does not store Monos, but the value inside them, so if we don’t have wrappers, then Mono.empty and Mono.error results will not be stored in the cache).
class ValueWrapper {
Something something;
boolean isError;
}
Mono<ValueWrapper> unCachedCallWrapper(ExampleKey key) {
return uncachedCall(key)
.map(something -> new ValueWrapper(something, false))
.onErrorReturn(new ValueWrapper(null, false))
}
The cache itself:
@Bean
AsyncLoadingCache<ExampleKey, ValueWrapper> exampleCache() {
return Caffeine.newBuilder()
.expireAfterWrite(2, TimeUnit.HOURS)
.maximumSize(200)
.buildAsync((ExampleKey key, Executor: executor) ->
unCachedCallWrapper(key)
.subscribeOn(Schedulers.fromExecutor(executor))
.toFuture() // Caffeine Cache does not support Monos directly, so we use a CompletableFuture
)
}
Using the cache:
Mono.fromFuture(exampleCache.get(new ExampleKey(...)));
The key type:
class ExampleKey {
// Equals method required so our cache keys are not just compared by object reference
@Override boolean equals(Object other) { ... }
}
Notes:
- To get
/actuator/caches
working correctly, the cache (and all the other caches) need to be have a CacheManagerCustomizer. - This link was very helpful:
https://gist.github.com/bijukunjummen/a12ab5d3e823c5f052ce608b5fc7b6a4