Spring Webflux中如何利用返回的retryTime配置RetryBackoffSpec动态退避
动态调整Reactor重试退避时长(基于服务器返回的retryTime)
你的现有代码使用固定退避时长的重试策略,但遇到服务器返回106响应时,需要改用服务器指定的retryTime来计算退避时长,同时保留抖动、重试次数等原有配置。可以通过以下步骤实现:
1. 定义自定义异常传递重试时长
创建一个异常类,用来携带服务器返回的retryTime,让重试逻辑能获取这个值:
public class ServerRetryException extends RuntimeException { private final long retryTimeSeconds; public ServerRetryException(long retryTimeSeconds) { this.retryTimeSeconds = retryTimeSeconds; } public long getRetryTimeSeconds() { return retryTimeSeconds; } }
2. 将106响应转为错误信号
在响应处理逻辑中,识别106响应并抛出上述自定义异常——因为retryWhen仅对错误信号触发重试,所以需要把正常返回的106响应转为错误信号:
Mono.fromCallable(() -> sendRequestToServer(params)) .doOnSuccess(result -> { // 请根据实际响应格式实现这两个方法 if (is106Response(result)) { long retryTime = parseRetryTimeFromResponse(result); throw new ServerRetryException(retryTime); } // 正常响应的处理逻辑 handleResponse(result, grantMapEntry, deviceInfo); })
3. 替换为自定义重试策略
放弃原来的RetryBackoffSpec.backoff(),改用Retry.custom()构建支持动态退避的重试策略,在backoff逻辑中读取异常里的retryTime:
.retryWhen(Retry.custom() // 保留原有最大重试次数 .maxAttempts(5) // 自定义退避时长:优先用服务器指定的retryTime,否则用默认10秒 .backoff(ctx -> { Throwable ex = ctx.exception(); if (ex instanceof ServerRetryException) { return Duration.ofSeconds(((ServerRetryException) ex).getRetryTimeSeconds()); } return Duration.ofSeconds(10); }) // 保留原有抖动配置 .jitter(0.5) // 保留原有重试调度器 .scheduler(hbRetryScheduler) // 优化重试日志,显示服务器指定的时长 .doAfterRetry(ctx -> { Throwable ex = ctx.exception(); String logMsg = ex instanceof ServerRetryException ? String.format("retrying after server-specified %ds", ((ServerRetryException) ex).getRetryTimeSeconds()) : "retrying"; log.warn(logMsg); }) // 可选:只对特定异常触发重试,避免无关错误重试 .filter(ctx -> ctx.exception() instanceof ServerRetryException || isRequestFailureException(ctx.exception())) ) .subscribe();
关键逻辑说明
- 异常传递:通过自定义异常把服务器返回的retryTime传递给重试策略,是实现动态退避的核心。
- 动态退避:
backoff()方法接收RetryContext,从中取出触发重试的异常,判断类型后选择对应的退避时长。 - 兼容原有配置:保留了原有的重试次数、抖动、调度器、日志逻辑,仅修改退避时长的计算方式。
内容的提问来源于stack exchange,提问作者quintin
相关产品推荐
相关产品推荐

