缓存和使缓存的 Mono 失效
Caching and invalidating cached Mono
我在尝试缓存 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));
}
目的是缓存用于接收Token
的Mono
,直到令牌过期。 token过期后,缓存的Mono
变空,请求新的token。
这按预期工作,但不幸的是 switchIfEmpty()
实际上并没有 "switch",而是包装了源 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>
(这将触发令牌检索)。
- 如果某个值已被缓存,并且新订阅在缓存超时之前到达,则缓存操作员会将缓存的值发送给新订阅者
- 如果一个值已被缓存,并且在缓存超时后新订阅到达,则缓存操作员将重新订阅从[返回的
Mono<Token>
=15=](这将触发令牌重新检索)。
- 如果从
getToken()
返回的 Mono<Token>
以异常完成,则该异常不会被缓存,因此会传播,下一个到达的订阅将重新触发令牌再次检索
这一切都假设:
getToken()
在订阅者到达之前不做任何工作
getToken()
检索每个订阅者的令牌
- 您只想为所有订阅者使用一个活动令牌
另请注意,根据您的用例,您可能希望令牌在到期日期之前稍微过期,以解决时钟偏差问题。即在新令牌实际到期之前先发制人地检索它,以防止返回 Token
,该令牌将在下游有机会使用它之前到期。
我在尝试缓存 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));
}
目的是缓存用于接收Token
的Mono
,直到令牌过期。 token过期后,缓存的Mono
变空,请求新的token。
这按预期工作,但不幸的是 switchIfEmpty()
实际上并没有 "switch",而是包装了源 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>
(这将触发令牌检索)。 - 如果某个值已被缓存,并且新订阅在缓存超时之前到达,则缓存操作员会将缓存的值发送给新订阅者
- 如果一个值已被缓存,并且在缓存超时后新订阅到达,则缓存操作员将重新订阅从[返回的
Mono<Token>
=15=](这将触发令牌重新检索)。 - 如果从
getToken()
返回的Mono<Token>
以异常完成,则该异常不会被缓存,因此会传播,下一个到达的订阅将重新触发令牌再次检索
这一切都假设:
getToken()
在订阅者到达之前不做任何工作getToken()
检索每个订阅者的令牌- 您只想为所有订阅者使用一个活动令牌
另请注意,根据您的用例,您可能希望令牌在到期日期之前稍微过期,以解决时钟偏差问题。即在新令牌实际到期之前先发制人地检索它,以防止返回 Token
,该令牌将在下游有机会使用它之前到期。