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

Spring Webflux WebClient任务未完成时重试失效问题排查

问题分析与修复方案

你的代码逻辑框架是正确的:POST获取jobId后发起GET查询状态,非COMPLETED状态时抛出可重试异常触发重试。但重试未触发,大概率是以下几个原因:

可能的问题点

  1. 重试参数配置错误:如果调用handleRetry时传入的maxAttempts为1,Reactor会认为已达到最大尝试次数(包含初始请求),不会执行任何重试。
  2. 重试逻辑无调试日志:无法确认重试逻辑是否被触发,缺少关键调试信息。
  3. 异常定义问题: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 13:58:13