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

Spring Reactive:retryWhen中backoff中断链路的原因探究

问题解答

两段代码的输出差异核心在于重试的执行机制和线程模型:

1. Retry.max(3)的执行逻辑

max模式是无延迟的立即重试,所有重试操作在订阅线程(此处为主线程)上同步连续执行:

  • 原调用触发StringIndexOutOfBoundsException后,会立刻启动重试,总共重试3次,每次重试前执行doBeforeRetry,因此打印3次该日志。
  • 3次重试全部失败后,异常会传递到下游的onErrorResume,执行错误恢复逻辑并返回默认值?,最终完成整个链路。

2. Retry.backoff(3, Duration.ofMillis(100))的执行逻辑

退避重试会引入延迟等待,且默认使用Schedulers.parallel()调度器执行延迟重试,而该调度器的线程是守护线程:

  • 第一次调用失败后,框架会调度一个延迟100ms的重试任务,但此时主线程已经执行完subscribe语句,没有任何阻塞逻辑,主线程直接结束。
  • JVM会在所有非守护线程终止后退出,守护线程会被强制停止,导致后续的重试任务、onErrorResume逻辑都没有执行机会。
  • 因此你只看到了第一次重试前的doBeforeRetry()日志,整个链路提前终止。

验证修复方案

如果要让退避重试的完整逻辑执行,只需让主线程保持存活,比如在subscribe后添加阻塞等待:

// 在subscribe后添加block()或sleep
.subscribe(System.out::println)
.block(); // 阻塞主线程直到整个流完成

此时就能看到和max模式类似的输出(会有100ms间隔的延迟):

doBeforeRetry()
doBeforeRetry()
doBeforeRetry()
onErrorResume()
?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 05:50:23