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

