在 Spring WebFlux Web 应用程序中缓存来自 WebClient 调用的 Mono 的结果 [英] Cache the result of a Mono from a WebClient call in a Spring WebFlux web application

查看:25
本文介绍了在 Spring WebFlux Web 应用程序中缓存来自 WebClient 调用的 Mono 的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望缓存一个 Mono(仅当它成功时),这是 WebClient 调用的结果.

I am looking to cache a Mono (only if it is successful) which is the result of a WebClient call.

从阅读项目反应堆插件文档我不觉得CacheMono 非常适合,因为它也缓存了我不想要的错误.

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.

因此,我不使用 CacheMono,而是执行以下操作:

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)));

这里我在 Mono 上调用缓存,然后将它添加到咖啡因缓存中.

Here I am calling cache on the Mono and then adding it to the caffeine cache.

任何错误都会进入 doOnError 以使缓存无效.

Any errors will enter doOnError to invalidate the cache.

这是缓存 Mono WebClient 响应的有效方法吗?

Is this a valid approach to caching a Mono WebClient response?

推荐答案

这是真正允许您调用非反应式库并用反应式类型包装它们并完成处理的极少数用例之一在像 doOnXYZ 这样的副作用操作符中,因为:

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:

  • Caffeine 是内存中的缓存,据我所知不涉及 I/O
  • 缓存通常不能为缓存值提供强有力的保证(它非常一劳永逸")

在这种情况下,您可以查询缓存以查看是否存在缓存版本(包装它并立即返回),并在 doOn 运算符中缓存成功的真实响应,如下所示:

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:

public class MyService {

    private WebClient client;

    private Cache<MyRequestObject, MyResponseObject> myCaffeineCache;

    public MyService() {
        this.client = WebClient.create();
        this.myCaffeineCache = Caffeine.newBuilder().maximumSize(100)
          .expireAfterWrite(Duration.ofSeconds(60)).build();
    }

    public Mono<MyResponseObject> fetchResponse(MyRequestObject request) {

        MyResponseObject cachedVersion = this.myCaffeineCache.get(myRequestObject);
        if (cachedVersion != null) {
           return Mono.just(cachedVersion);
        } else {
           return this.client.post()
                         .uri("http://www.example.com")
                         .syncBody(request.getKey())
                         .retrieve()
                         .bodyToMono(MyResponseObject.class)
                         .doOnNext(response -> this.myCaffeineCache.put(request.getKey(), response));
    }
}

请注意,我不会在这里缓存反应类型,因为一旦缓存返回值,就不会涉及 I/O 或背压.相反,订阅和其他反应性流限制使事情变得更加困难.

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.

此外,您对 cache 操作符的看法是正确的,因为它不是缓存值本身,而是重放其他订阅者发生的事情.我相信 cachereplay 操作符实际上是 Flux 的同义词.

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 that cache and replay operators are actually synonyms for Flux.

这篇关于在 Spring WebFlux Web 应用程序中缓存来自 WebClient 调用的 Mono 的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆