因此,我的应用程序将多次拨打昂贵的HTTP服务(同时通过多个线程,以及每个客户端请求的不同ID以及不同的ID)。
Mono<Foo> response = myService.fetch(id);
我想缓存响应(内存中)几个小时,然后仅在下一个客户端请求时只拨打一个调用来刷新缓存。
方法1:
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的方法。另外,当缓存在4小时后无效时,是否会使cachedresponse mono空为空?
方法2:我可以使用一些缓存解决方案存储缓存几个小时。例如
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行将被称为多次,导致多次调用昂贵的获取服务(例如,如果3个线程输入具有ID 123的GET方法,而Cachedfoo且cachedfoo为null)。使方法同步可能无济于事,因为第7行将立即完成。
一个工作要做的是将单声道存储在缓存解决方案中,而不是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;
}));
}
任何建议或更好的替代方案?
您的问题由两个部分组成:关于缓存和具有相同参数的呼叫的独家锁定。
-
缓存。
您的第二种方法非常适合内存缓存。另外,您可以使用反应器-Extra
中的CacheMono
Mono<Foo> myFoo = CacheMono.lookup(key -> Mono.justOrEmpty(myCache.getIfPresent(key)) .map(Signal::next), id) .onCacheMissResume(() -> myService.fetch(id)) .andWriteWith((key, signal) -> Mono.fromRunnable(() -> Optional.ofNullable(signal.get()) .ifPresent(value -> myCache.put(key, value))));
-
具有相同参数的呼叫的独家锁定。
通常,我们应该避免在反应世界中锁定任何锁定。但是,如果您真的需要它,那么您的锁应该是不封锁的。我不知道任何库,但是您可以在此问题线程中找到一些想法和链接