我对网络流量很陌生,我正在尝试实现这个场景:
如果数据已经存在于redis缓存中,则
的远程服务。
我写了这段代码:
ReactiveRedisOperations<String, Foo> redisOps;
private Mono<Foo> getFoo(String k) {
return this.redisOperations.opsForValue().get(k)
.map(f -> this.logCache(k, f))
.switchIfEmpty(this.queryRemoteService(k));
}
private void logCache(String k, Foo f) {
this.logger.info("Foo # {} # {} present in cache. {}",
k,
null != f ? "" : "NOT",
null != f ? "" : "Querying remote");
}
private Mono<Foo> queryRemoteService(String k) {
this.logger.info("Querying remote service");
// query code
}它打印:
"Querying remote service"
"Foo # test_key # present in cache"如何确保仅当缓存的数据不存在时才调用switchIfEmpty?
编辑
因此,对于Michael的回答,我将代码重构如下:
private Mono<Foo> getFoo(String k) {
this.logger.info("Trying to get cached {} data", k);
this.logger.info(this.redisOps.hasKey(k).block() ? "PRESENT" : "NOT present");
return this.redisOperations.opsForValue().get(k)
.switchIfEmpty(this.queryRemoteService(k));
}
private Mono<Foo> queryRemoteService(String k) {
this.logger.info("Querying remote service");
// query code
}现在我的输出是:
Trying to get cached test_key data
PRESENT
Querying provider因此,似乎只执行了一次,但仍然无法避免执行switchIfEmpty。我确信redis包含了该密钥的数据
发布于 2019-11-21 12:17:57
这一行:
.map(f -> this.logCache(k, f))...is相当奇怪,因为您没有将任何东西映射到任何东西,而是执行一个副作用(记录值。),在这里,doOnNext() (而不是map())将是一个更明智的选择。
不过,我离题了,这不是主要的问题。
如何确保仅当缓存的数据不存在时才调用
switchIfEmpty?
已经是这样了,但你的日志记录并没有像你想的那样。这里可能引起问题的关键概念是,null永远不能通过反应流传播。如果流是空的,如本例所示,则不会传播任何内容。
因此,在您的代码中,不会调用map() (如果使用的话也不会调用doOnNext() ),因此您的“存在缓存”行不会写入日志(因为没有要映射的值,也没有可以调用副作用的值)。因此,检查logCache()中的值是否为空是没有意义的--它永远不会是空的。
因此,在我看来,这里的日志输出必须是两个getFoo()调用的结果。
map(),没有调用switchIfEmpty()交换,并且打印了“查询远程服务”;在缓存中显示了switchIfEmpty(),因此没有打印“查询远程服务”。要使您的日志记录有意义,您应该从logCache()中删除条件逻辑,并将“不在缓存中”行添加到queryRemoteService()方法中。
https://stackoverflow.com/questions/58974349
复制相似问题