缓存和使缓存的单声道失效



我在尝试缓存WebClient返回的Mono时遇到了问题。代码是这样的:

public Mono<Token> authenticate() {
return cachedTokenMono = cachedTokenMono
.switchIfEmpty(
Mono.defer(() -> 
getToken())
.cache(token ->
Duration.between(Instant.now(), token.getExpires().toInstant()),
(Throwable throwable) -> Duration.ZERO,
() -> Duration.ZERO));
}

目的是缓存用于接收TokenMono,直到令牌过期。令牌过期后,缓存的Mono将变为空,并请求新令牌。 这按预期工作,但不幸的是switchIfEmpty()实际上并没有"切换",而是将源包装Mono。因此,随着越来越多的包装SwitchIfEmptyMono的创建,这会产生内存泄漏。 在这种情况下,正确的模式是什么?有没有办法用新的Mono代替空的?

你可以做这样的事情:

private final Mono<Token> authenticateMono = getToken()
.cache(
token -> Duration.between(Instant.now(), token.getExpires().toInstant()),
throwable -> Duration.ZERO,
() -> Duration.ZERO)
public Mono<Token> authenticate() {
return authenticateMono;
}

这个想法是,您为每次调用authenticate()返回相同的缓存Mono<Token>实例。.cache运算符确保检查每个订阅的缓存结果。

具体说来:

  • 如果新订阅到达并且没有缓存值,则缓存运算符将订阅从getToken()返回的Mono<Token>(这将触发令牌检索)。
  • 如果已缓存值,并且新订阅在缓存
  • 超时之前到达,则缓存运算符会将缓存的值发送到新订阅者
  • 如果已缓存值,并且在缓存超时到达新订阅,则缓存运算符将重新订阅从getToken()返回的Mono<Token>(这将触发令牌重新检索)。
  • 如果从getToken()返回的Mono<Token>完成并出现异常,则不会缓存该异常,因此会传播,到达的下一个订阅将再次重新触发令牌检索

这一切都假设:

  • getToken()在订阅者到达之前不执行任何工作
  • getToken()检索每个订阅者的令牌
  • 您只需要所有订阅者使用一个活动令牌

另请注意,根据您的用例,您可能希望在令牌到期日期之前稍早过期,以解决时钟偏差。 即在新令牌实际过期之前抢占先检索新令牌,以防止返回在下游有机会使用它之前将过期的Token

最新更新