You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Reactor Stream异常排查:调用getDeliveryDate无Redis写入无日志输出

问题分析:调用Reactor方法无响应的原因及解决

问题背景

代码逻辑为:getDeliveryDate方法先尝试从Redis获取数据,若不存在则调用getFallbackValue方法;该方法通过WebClient调用API获取数据并转为字符串。但在main方法中调用getDeliveryDate(id, info)后无任何反应——既无数据写入Redis,log.info("value***** {}", value)也无日志输出,已知client.getDeliveryDateInfo(id)返回Mono类型。

代码片段

调用代码

getDeliveryDate(id, info);

业务处理方法

public void getDeliveryDate(String id, Info info) {
    service.getDeliveryDate(id)
           .doOnNext(value -> log.info("value***** {}", value))
           .map(deliveryDateInfo -> info.deliveryDateInfo(deliveryDateInfo))
           .switchIfEmpty(Mono.fromSupplier(() -> {
               itemInfo.setErrorCode("error");
               return info;
           }));
}

Redis查询与回退逻辑

public Mono<String> getDeliveryDate(String id) {
    final String key = id;
    return deliveryDateOperations.opsForValue()
                                 .get(key)
                                 .switchIfEmpty(getFallbackValue(id))
                                 .flatMap(value -> deliveryDateOperations.opsForValue()
                                                                         .setIfAbsent(key, value, ttl)
                                                                         .thenReturn(value));
}

远程API调用方法

Mono<String> getFallbackValue(String id) {
    return client.getDeliveryDateInfo(id)
                 .map(response -> convertDataToString(response));
}

核心问题原因

Reactor(Spring WebFlux基于此框架)的Mono/Flux属于冷流——只有当存在**订阅(subscribe)**操作时,整个数据流才会被触发执行。你的代码存在以下关键问题:

  • 在getDeliveryDate方法中,仅构建了Mono的操作链,但未调用subscribe()或类似的订阅方法
  • 没有触发订阅,所有后续操作(Redis查询、WebClient调用、日志打印、Redis写入)都不会实际执行

解决方案

需要在操作链末尾添加订阅操作,根据场景选择合适的方式:

方式1:直接在方法内调用subscribe()(适用于简单场景)

修改getDeliveryDate方法,添加订阅触发执行:

public void getDeliveryDate(String id, Info info) {
    service.getDeliveryDate(id)
           .doOnNext(value -> log.info("value***** {}", value))
           .map(deliveryDateInfo -> info.deliveryDateInfo(deliveryDateInfo))
           .switchIfEmpty(Mono.fromSupplier(() -> {
               itemInfo.setErrorCode("error");
               return info;
           }))
           // 添加订阅触发整个数据流执行
           .subscribe();
}

方式2:返回Mono让上层调用者订阅(符合响应式编程规范)

如果是在响应式环境(如WebFlux接口)中,建议不要在方法内部订阅,而是返回Mono交给上层处理:

public Mono<Info> getDeliveryDate(String id, Info info) {
    return service.getDeliveryDate(id)
                  .doOnNext(value -> log.info("value***** {}", value))
                  .map(deliveryDateInfo -> info.deliveryDateInfo(deliveryDateInfo))
                  .switchIfEmpty(Mono.fromSupplier(() -> {
                      itemInfo.setErrorCode("error");
                      return info;
                  }));
}

调用处添加订阅:

getDeliveryDate(id, info).subscribe();

额外注意事项

  • 若在Spring WebFlux的Controller中,直接返回Mono即可,框架会自动处理订阅
  • 如需处理订阅过程中的异常,可在subscribe中添加错误处理器:.subscribe(result -> {}, error -> log.error("执行失败", error))

内容的提问来源于stack exchange,提问作者george jiang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 03:07:23