Spring Retry重复请求及CircuitBreaker配置后重试异常问题咨询
问题根因
- 重试逻辑嵌套叠加:你当前用了两层重试相关注解,外层
Status类的getStatus方法加了@Retryable,内层StatusClient的方法加了Spring Retry提供的@CircuitBreaker,而Spring Retry的@CircuitBreaker本身内置了重试逻辑,两层重试规则叠加导致触发了预期外的重复调用。 - 异常触发逻辑未做限制:你没有为重试注解指定触发异常的范围,所有向上抛出的异常(包括服务端返回错误、响应体反序列化异常、甚至内部运行时异常)都会触发重试。你第一次观测到的两次成功请求,大概率是第一次请求已经成功拿到远端响应,但后续反序列化或者处理过程中抛出了瞬态异常,触发重试后第二次调用完全成功,因此打印了两次成功日志。
- 配置参数含义混淆:
@CircuitBreaker的maxAttempts参数指的是断路器打开前允许的连续失败次数,而非重试次数。你将该参数改为1后,第一次调用远端返回503触发异常,断路器直接打开,后续外层@Retryable的剩余2次重试请求会被断路器直接拦截,抛出ExhaustedRetryException,不会发起实际远端调用,刚好匹配你配置的retry.maxAttempts=3的总尝试次数。
解决方法
- 移除重复重试逻辑:二选一重试方案即可,不需要嵌套注解:
- 保留
@CircuitBreaker,删除外层的@Retryable注解,直接在@CircuitBreaker中配置重试和熔断规则即可覆盖需求 - 若要单独用
@Retryable控制重试,可将@CircuitBreaker的maxAttempts设为1,关闭其内置重试能力,仅保留熔断功能
- 保留
- 明确重试触发范围:给重试注解增加
include属性,仅对需要重试的异常(如网络异常、远端返回5xx错误抛出的RemoteClientException等)触发重试,避免无差别重试:@Retryable(include = {RemoteClientException.class, java.io.IOException.class}, maxAttemptsExpression = "#{${remote.retry.maxAttempts}}", backoff = @Backoff(delayExpression = "#{${remote.retry.delay}}")) - 补充排查日志:在方法入口增加调用次数日志,同时捕获完整异常栈打印,确认每次重试触发的具体原因,避免隐性异常导致的误重试。
内容的提问来源于stack exchange,提问作者Chandresh Mishra
相关产品推荐
相关产品推荐

