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

Spring Boot中如何实现动态可变延迟时间的重试机制?

解决方案

要实现按配置的固定延迟序列进行重试,你需要自定义重试策略,而非依赖默认的指数退避Retry.backoff。以下是具体实现步骤:

1. 配置延迟列表

在application.yml中定义重试延迟序列:

retry:
  delays: [1, 3, 10, 30, 120, 200, 360, 450] # 单位:秒

创建配置类加载该列表并转换为Duration集合:

@Configuration
@ConfigurationProperties(prefix = "retry")
public class RetryConfig {
    private List<Long> delays;

    public List<Duration> getDelayDurations() {
        return delays.stream()
                .map(Duration::ofSeconds)
                .collect(Collectors.toList());
    }

    // Getters and Setters
    public List<Long> getDelays() {
        return delays;
    }

    public void setDelays(List<Long> delays) {
        this.delays = delays;
    }
}

2. 定义重试触发的异常

创建自定义异常类,明确标识需要重试的场景:

// 捕获5xx状态码的异常
public class ServerErrorException extends RuntimeException {
    public ServerErrorException(String message) {
        super(message);
    }
}

// 捕获结果为null的异常
public class NullResultException extends RuntimeException {
    public NullResultException(String message) {
        super(message);
    }
}

3. 配置WebClient的重试逻辑

修改原有WebClient代码,加入异常捕获和自定义重试策略:

@Autowired
private RetryConfig retryConfig;

// 请求地址常量
private static final String GET_STUDENTS_URL = "/api/students";

public Flux<Student> getStudents() {
    return WebClient.create()
            .get()
            .uri(GET_STUDENTS_URL)
            .retrieve()
            // 将5xx状态码转换为自定义异常,触发重试
            .onStatus(HttpStatus::is5xxServerError, response ->
                    Mono.error(new ServerErrorException("Server returned 5xx status: " + response.statusCode())))
            .bodyToFlux(Student.class)
            // 检查返回元素是否为null,触发重试
            .doOnNext(student -> {
                if (student == null) {
                    throw new NullResultException("Received null Student object");
                }
            })
            // 自定义重试策略:按配置的延迟序列依次执行
            .retryWhen(Retry.from(companion ->
                    companion.zipWith(Flux.fromIterable(retryConfig.getDelayDurations()))
                            .flatMap(tuple -> {
                                RetrySignal signal = tuple.getT1();
                                Duration delay = tuple.getT2();

                                // 仅对指定异常执行重试
                                if (signal.failure() instanceof ServerErrorException ||
                                    signal.failure() instanceof NullResultException) {
                                    return Mono.delay(delay);
                                }

                                // 其他异常直接抛出,终止重试流程
                                return Mono.error(signal.failure());
                            })
            ));
}

关键说明

  • 重试次数由application.yml中延迟列表的长度决定:列表有8个值时,最多重试8次(加上初始请求共9次调用)。
  • 仅对ServerErrorException(5xx状态)和NullResultException(结果为null)触发重试,其他异常直接抛出。
  • 若需处理整个返回结果为空的场景,可在bodyToFlux后加入switchIfEmpty(Mono.error(new EmptyResultException("No data returned"))),并将EmptyResultException加入重试判断逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 05:27:38