Reactive:缓存服务响应几个小时

问题描述 投票:1回答:1

因此,我的应用程序将多次调用以下昂贵的HTTP服务(同时由多个线程同时以及每个客户端请求到我的应用程序的不同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的get方法。此外,当缓存在4小时后失效时,是否会使cachedResponse Mono为空以使switchIfEmpty正常工作?

方法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为null)。使方法同步可能没有帮助,因为第7行将立即完成。

一个解决方法是将Mojo存储在缓存解决方案而不是Food中(不确定这是不是一个好主意):

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

任何建议或更好的选择?

java spring spring-webflux project-reactor
1个回答
1
投票

您的问题由两部分组成:缓存和具有相同参数的调用的独占锁定。

  1. 缓存。 您的第二种方法适用于内存缓存。或者你可以使用CacheMonoreactor-extra 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))));
  2. 具有相同参数的呼叫的独占锁定。 通常我们应该避免在被动世界中的任何锁定。但如果你真的需要它,你的锁应该是非阻塞的。我不知道任何图书馆,但你可以在this question thread找到一些想法和链接
© www.soinside.com 2019 - 2024. All rights reserved.