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
相关产品推荐
相关产品推荐

