【发布时间】:2019-07-20 07:15:01
【问题描述】:
所以我的应用程序会多次调用下面昂贵的 HTTP 服务(同时由多个线程对我的应用程序的每个客户端请求具有相同和不同的 Id)。
Mono<Foo> response = myService.fetch(id);
我想将响应缓存(在内存中)几个小时,然后仅在下一个客户端请求时只调用一次来刷新缓存。
方法一:
Mono<Foo> cachedResponse = Mono.empty();
public Mono<Foo> get(String id){
return cachedResponse.switchIfEmpty(Mono.defer(()->
{
cachedResponse = myService.fetch(id).cache(Duration.ofHours(4));
return cachedResponse;
}));
}
以下方法可以吗?特别是因为多个线程可以调用具有相同 id 的 get 方法。另外,当缓存在 4 小时后失效时,是否会使 cachedResponse Mono 为空,以便 switchIfEmpty 正常工作?
方法二: 我可以使用一些缓存解决方案来存储缓存几个小时。例如
Foo getFromCacheSolution(String id);
然后,
public Mono<Foo> get(String id){
Foo cachedFoo = getFromCacheSolution(id);
if(cachedFoo != null){
return Mono.just(cachedFoo);
}
else{
return myService.fetch(id).doOnNext(value->storeToCacheSolution(id, value)); //line 7
}
}
这个解决方案的问题是第 7 行会被多次调用,从而导致多次调用昂贵的 fetch 服务(例如,如果 3 个线程进入 id 为 123 的 get 方法并且 cachedFoo 为空)。使方法同步可能无济于事,因为第 7 行会立即完成。
一种解决方法是将 Mono 存储在缓存解决方案中而不是 Foo 中(不确定这是否是个好主意):
Mono<Foo> getFromCacheSolution(String id); //returns cached or empty Mono
然后,
public Mono<Foo> get(String id){
return getFromCacheSolution(id).switchIfEmpty(Mono.defer(()->
{
cachedResponse = myService.fetch(id).doOnNext(value->storeToCacheSolution(id, value));
return cachedResponse;
}));
}
有什么建议或更好的选择吗?
【问题讨论】:
-
我更喜欢第二种解决方案,但可能来自 reactor-extra 项目的caching helper 可以在这里提供帮助?
标签: java spring spring-webflux project-reactor