Spring Webflux WebClient任务未完成时重试失效问题排查
问题分析与修复方案
你的代码逻辑框架是正确的:POST获取jobId后发起GET查询状态,非COMPLETED状态时抛出可重试异常触发重试。但重试未触发,大概率是以下几个原因:
可能的问题点
- 重试参数配置错误:如果调用
handleRetry时传入的maxAttempts为1,Reactor会认为已达到最大尝试次数(包含初始请求),不会执行任何重试。 - 重试逻辑无调试日志:无法确认重试逻辑是否被触发,缺少关键调试信息。
- 异常定义问题:
RetryableException如果不是RuntimeException子类,可能被Reactor的错误处理逻辑拦截,导致重试不生效。
修复步骤
1. 修正重试参数
确保调用handleRetry时传入的maxAttempts大于1(比如设置为10,允许最多9次重试),backoff设置为1(对应1秒重试间隔):
// 示例调用 .retryWhen(handleRetry(10, 1))
2. 完善重试逻辑的日志与配置
修改handleRetry方法,添加重试前的日志输出,同时确保只对RetryableException进行重试:
public static RetryBackoffSpec handleRetry(Integer maxAttempts, Integer backoff) { log.info("初始化重试配置: maxAttempts={}, backoff={}s", maxAttempts, backoff); return Retry.backoff(maxAttempts, Duration.ofSeconds(backoff)) .filter(throwable -> throwable instanceof RetryableException) .doBeforeRetry(retrySignal -> { RetryableException ex = (RetryableException) retrySignal.failure(); log.info("重试任务状态检查 (第 {}/{} 次尝试): {}", retrySignal.totalRetries() + 1, maxAttempts, ex.getMessage()); }) .onRetryExhaustedThrow((spec, signal) -> { RetryableException ex = (RetryableException) signal.failure(); log.error("重试{}次后仍未完成任务", maxAttempts); return getApiException(ex.getError(), signal.failure()); }); }
3. 确认RetryableException的定义
确保RetryableException继承自RuntimeException,避免被视为Checked异常拦截:
public class RetryableException extends RuntimeException { private final ApiError error; public RetryableException(ApiError error, String message) { super(message); this.error = error; } public ApiError getError() { return error; } }
4. 可选:改用Retry.from实现更直观的重试逻辑
如果想更灵活地控制重试流程,可以替换为Retry.from方式:
public static Retry handleRetry(Integer maxAttempts, Integer backoff) { log.info("初始化重试配置: maxAttempts={}, backoff={}s", maxAttempts, backoff); return Retry.from(companion -> companion .filter(RetryableException.class::isInstance) .zipWith(Flux.range(1, maxAttempts), (signal, attempt) -> attempt) .flatMap(attempt -> { log.info("等待{}秒后执行第{}次重试", backoff, attempt); return Mono.delay(Duration.ofSeconds(backoff)); }) .onErrorMap(throwable -> { if (throwable instanceof RetryableException) { return getApiException(((RetryableException) throwable).getError(), throwable); } return throwable; }) ); }
验证修复
修改后,当GET请求返回IN_PROGRESS/PENDING状态时,控制台会打印重试日志,且1秒后自动发起新的GET请求;当达到最大重试次数仍未完成时,会抛出ApiException。
内容的提问来源于stack exchange,提问作者Karthik Sharma
相关产品推荐
相关产品推荐

