I am looking to cache a Mono
(only if it is successful) which is the result of a WebClient call.
From reading the project reactor addons docs I don't feel that CacheMono is a good fit as it caches the errors as well which I do not want.
So instead of using CacheMono
I am doing the below:
Cache<MyRequestObject, Mono<MyResponseObject>> myCaffeineCache =
Caffeine.newBuilder()
.maximumSize(100)
.expireAfterWrite(Duration.ofSeconds(60))
.build();
MyRequestObject myRequestObject = ...;
Mono<MyResponseObject> myResponseObject = myCaffeineCache.get(myRequestObject,
requestAsKey -> WebClient.create()
.post()
.uri("http://www.example.com")
.syncBody(requestAsKey)
.retrieve()
.bodyToMono(MyResponseObject.class)
.cache()
.doOnError(t -> myCaffeineCache.invalidate(requestAsKey)));
Here I am calling cache on the Mono
and then adding it to the caffeine cache.
Any errors will enter doOnError
to invalidate the cache.
Is this a valid approach to caching a Mono
WebClient response?
Actually, you don't have to save errors with CacheMono.
When you switch to external cache, this may be usefull. Don't forget using reactive clients for external caches.
This is one of the very few use cases where you'd be actually allowed to call non-reactive libraries and wrap them with reactive types, and have processing done in side-effects operators like
doOnXYZ
, because:You can then in this case query the cache to see if a cached version is there (wrap it and return right away), and cache a successful real response in a
doOn
operator, like this:Note that I wouldn't cache reactive types here, since there's no I/O involved nor backpressure once the value is returned by the cache. On the contrary, it's making things more difficult with subscription and other reactive streams constraints.
Also you're right about the
cache
operator since it isn't about caching the value per se, but more about replaying what happened to other subscribers. I believe thatcache
andreplay
operators are actually synonyms forFlux
.