Springboot-Guava retrying接口重试

        

目录

一、maven 依赖

二、创建重试器并执行重试

三、重试监听


        一般在各种业务场景中,为了保持系统稳定,我们都会有相应的重试机制,某个接口某个数据库链接由于网络抖动或者其他因素导致响应失败。

        Guava-retrying或者分析过其源码你会发现,guava-retrying重试组件特别轻量级,核心类就那几个,并且使用简单设计优雅,但是它也存在缺点。

优点

  1. 策略丰富并且支持自定义
  2. 使用简单
  3. 设计优雅

缺点

  1. 不支持注解
  2. 侵入业务代码
  3. 重复性强

一、maven 依赖

2.0.0

      com.github.rholder
      guava-retrying
      ${guava-retry.version}

二、创建重试器并执行重试

import cn.meng.listener.RestTemplateRetryListener;
import cn.hutool.core.util.ObjectUtil;
import com.github.rholder.retry.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Author: meng
 * @Description: http
 * @Date: 2022/8/28 09:35
 * @Version: 1.0
 */
@Slf4j
@Service
public class HttpService {

	@Resource
	private RestTemplate httpsRestTemplate;

	private Retryer> retryer = RetryerBuilder
			.>newBuilder()
			// retryIf 重试条件
			.retryIfResult(Objects::isNull)
			// 本次尝试失败后,过3秒再次尝试
			.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
			// 总共尝试3次
			.withStopStrategy(StopStrategies.stopAfterAttempt(3))
			// 遇到运行时异常才重试
			.retryIfRuntimeException()
			.withRetryListener(new RestTemplateRetryListener<>())
			.build();

	public ResponseEntity exchange(String token, String url, String data) {
		Callable> getResponseEntity = new Callable>() {
			@Override
			public ResponseEntity call() throws Exception {
				//构建headers
				HttpHeaders httpHeaders = new HttpHeaders();
				httpHeaders.set(CommonConstant.HEADER_TOKEN, token);
				httpHeaders.setContentType(MediaType.APPLICATION_JSON);
				HttpEntity httpEntity = new HttpEntity<>(data, httpHeaders);
				return httpsRestTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
			}
		};

		ResponseEntity responseEntity = null;
		try {
			responseEntity = retryer.call(getResponseEntity);
		} catch (RetryException | ExecutionException e) {
			e.printStackTrace();
		}
		if(ObjectUtil.isNull(responseEntity)) {
			throw new CommonErrorException("调用服务网络异常");
		}
		return responseEntity;
	}

}

三、重试监听

import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryListener;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author: meng
 * @Description: 重试监听
 * @Date: 2022/10/10 19:22
 * @Version: 1.0
 */
@Slf4j
public class RestTemplateRetryListener implements RetryListener {
	@Override
	public  void onRetry(Attempt attempt) {
		// 第几次重试;距离第一次重试的延迟;重试结果: 是异常终止, 还是正常返回
		log.info("[retry]time=" + attempt.getAttemptNumber() + ",delay=" + attempt.getDelaySinceFirstAttempt()
				+ ",hasException=" + attempt.hasException() + ",hasResult=" + attempt.hasResult());
		// 是什么原因导致异常
		if (attempt.hasException()) {
			log.error("RestTemplate,causeBy=" + attempt.getExceptionCause().toString());
		}
	}
}

Attemp

        Attemp既是一次任务重试(call),也是一次请求的结果,记录了当前请求的重试次数,是否包含异常和请求的返回值。我们可以配合监听器使用,用于记录重试过程的细节,常用的方法有如下几个:

  •     getAttemptNumber(),表示准备开始第几次重试;
  •     getDelaySinceFirstAttempt(),表示距离第一次重试的延迟,也就是与第一次重试的时间差,单位毫秒;
  •     hasException(),表示是异常导致的重试还是正常返回;
  •     hasResult(),表示是否返回了结果;因为有时候是因为返回了特定结果才进行重试;
  •     getExceptionCause(),如果是异常导致的重试,那么获取具体具体的异常类型;
  •     getResult(),返回重试的结果;
  •     get(),如果有的话,返回重试的结果;和getResult不同的在于对异常的处理;

Springboot-Guava retrying接口重试_第1张图片

相关学习链接:guava-retry介绍_赶路人儿的博客-CSDN博客_guava-retrying

你可能感兴趣的:(#,SpringBoot,经验总结,guava,java,springboot)