这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战
第三方服务之重试机制
业务上存在一个功能是实现推送服务,利用内部服务的RocketMQ推送数据到服务后,推送到用户指定的url地址
2.1为什么需要重试
不谈整个功能的实现,在实现该功能的时候,容易出现一个小问题——推送失败重试; 明面上是推送的功能,其实就是内部调用API,在服务端内部利用restTemplate 调用HTTP请求。并且需要保证HTTP请求在可控的范围内
然而如果用HTTP推送到客户的接口地址的话,失败的追溯、重试等问题都需要受到重视并追溯.
- 如果单纯自己实现重试+追溯的话,可能需要依靠恶心的try/catch 里面的catch实现业务逻辑——错误日志
- 重试的话,可能需要自己利用局部变量去不断循环调用该接口
-
public Boolean doPush(DeviceDataDto dto) { //设置重试次数 int retries = 0; while (true){ try { return doRetryPush(dto, header, retries); }catch (Exception e){ if (retries == 1){ throw e; } retries++; } } }
很显然,这样并不优雅,也会存在较大的隐患
2.2 利用Spring-retry
利用Spring-retry 实现重试机制
-
只需引入依赖
- 依赖包括Spring retry的重试
- 以及借助AOP的切面
<!--Spring retry--> <dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> -
代码层实现注解的加入
-
@Retryable
- value:指定Exception类型
- maxAttempts:重试次数
- backoff:默认为@Backoff,delay:失败后回调次数;multiplier:失败后偏移量
-
@Recover:失败后达到指定阈值后调用方法(自定义)
- 加入该注解可以自定义回调方法
- 在本次的功能上,自定义失败回调方法,可以在平台内有一个日志报表,记录推送失败的日志;该日志由异步回调方法编写业务
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 1.5)) public int minGoodsnum(int num) throws Exception { log.info("网络请求开始" + LocalTime.now()); try { Future<FarmWeatherDTO> future = taskDeom.taskCity(); future.get(); } catch (Exception e) { throw new IllegalArgumentException("网络请求失败"); } log.info("网络请求结束" + LocalTime.now()); return totalNum - num; } @Recover public int rover(Exception e){ log.warn("网络请求失败!!!" + LocalTime.now()); return totalNum; } -