0.0.2.0
实现链路管控
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 267 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 0 B |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 0 B |
@ -3,10 +3,10 @@
|
|||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>com.x.retry</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>x-retry</artifactId>
|
||||||
<version>2.5.6</version>
|
<version>${revision}</version>
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.example</groupId>
|
<groupId>com.example</groupId>
|
||||||
@ -38,7 +38,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.x.retry</groupId>
|
<groupId>com.x.retry</groupId>
|
||||||
<artifactId>x-retry-client-starter</artifactId>
|
<artifactId>x-retry-client-starter</artifactId>
|
||||||
<version>0.0.1.0</version>
|
<version>0.0.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
|
@ -1,18 +1,24 @@
|
|||||||
package com.example;
|
package com.example;
|
||||||
|
|
||||||
|
import com.x.retry.client.core.exception.XRetryClientException;
|
||||||
import com.x.retry.client.core.intercepter.RetrySiteSnapshot;
|
import com.x.retry.client.core.intercepter.RetrySiteSnapshot;
|
||||||
import com.x.retry.common.core.constant.SystemConstants;
|
import com.x.retry.common.core.constant.SystemConstants;
|
||||||
|
import com.x.retry.common.core.log.LogUtils;
|
||||||
import com.x.retry.common.core.model.XRetryHeaders;
|
import com.x.retry.common.core.model.XRetryHeaders;
|
||||||
import com.x.retry.common.core.util.JsonUtil;
|
import com.x.retry.common.core.util.JsonUtil;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpRequest;
|
import org.springframework.http.HttpRequest;
|
||||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* RestTemplate 拦截器
|
||||||
|
*
|
||||||
* @author: shuguang.zhang
|
* @author: shuguang.zhang
|
||||||
* @date : 2022-04-17 15:22
|
* @date : 2022-04-17 15:22
|
||||||
*/
|
*/
|
||||||
@ -20,11 +26,44 @@ public class ExampleClientHttpRequestInterceptor implements ClientHttpRequestInt
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
|
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
|
||||||
XRetryHeaders retryHeader = RetrySiteSnapshot.getRetryHeader();
|
|
||||||
if (Objects.nonNull(retryHeader)) {
|
|
||||||
request.getHeaders().add(SystemConstants.X_RETRY_HEAD, JsonUtil.toJsonString(retryHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
return execution.execute(request, body);
|
before(request);
|
||||||
|
|
||||||
|
ClientHttpResponse execute = execution.execute(request, body);
|
||||||
|
|
||||||
|
after(execute);
|
||||||
|
|
||||||
|
return execute;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void after(ClientHttpResponse execute) {
|
||||||
|
|
||||||
|
HttpHeaders headers = execute.getHeaders();
|
||||||
|
|
||||||
|
// 获取不重试标志
|
||||||
|
if (headers.containsKey(SystemConstants.X_RETRY_STATUS_CODE_KEY)) {
|
||||||
|
List<String> statusCode = headers.get(SystemConstants.X_RETRY_STATUS_CODE_KEY);
|
||||||
|
RetrySiteSnapshot.setRetryStatusCode(statusCode.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void before(HttpRequest request) {
|
||||||
|
|
||||||
|
XRetryHeaders retryHeader = RetrySiteSnapshot.getRetryHeader();
|
||||||
|
|
||||||
|
// 传递请求头
|
||||||
|
if (Objects.nonNull(retryHeader)) {
|
||||||
|
long callRemoteTime = System.currentTimeMillis();
|
||||||
|
long entryMethodTime = RetrySiteSnapshot.getEntryMethodTime();
|
||||||
|
long transmitTime = retryHeader.getDdl() - (callRemoteTime - entryMethodTime);
|
||||||
|
LogUtils.info("RPC传递header头 entryMethodTime:[{}] - callRemoteTime:[{}] = transmitTime:[{}]", entryMethodTime, callRemoteTime, transmitTime);
|
||||||
|
if (transmitTime > 0) {
|
||||||
|
retryHeader.setDdl(transmitTime);
|
||||||
|
} else {
|
||||||
|
throw new XRetryClientException("调用链超时, 不在继续调用后面请求");
|
||||||
|
}
|
||||||
|
|
||||||
|
request.getHeaders().add(SystemConstants.X_RETRY_HEAD_KEY, JsonUtil.toJsonString(retryHeader));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package com.example.controller;
|
package com.example.controller;
|
||||||
|
|
||||||
|
import com.x.retry.client.core.intercepter.RetrySiteSnapshot;
|
||||||
import com.x.retry.common.core.constant.SystemConstants;
|
import com.x.retry.common.core.constant.SystemConstants;
|
||||||
import com.x.retry.common.core.model.Result;
|
import com.x.retry.common.core.model.Result;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -23,10 +23,20 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
public class SchoolController {
|
public class SchoolController {
|
||||||
|
|
||||||
@GetMapping("/id")
|
@GetMapping("/id")
|
||||||
public Result getSchool(HttpServletRequest request) {
|
public Result getSchool(HttpServletRequest request, HttpServletResponse response) {
|
||||||
String header = request.getHeader(SystemConstants.X_RETRY_HEAD);
|
|
||||||
|
String header = request.getHeader(SystemConstants.X_RETRY_HEAD_KEY);
|
||||||
System.out.println(header);
|
System.out.println(header);
|
||||||
return new Result("school");
|
|
||||||
|
if (RetrySiteSnapshot.isRetryFlow()) {
|
||||||
|
response.addHeader(SystemConstants.X_RETRY_STATUS_CODE_KEY, SystemConstants.X_RETRY_STATUS_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
throw new UnsupportedOperationException("异常测试");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Result(0, "school");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package com.example.controller;
|
package com.example.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.x.retry.client.core.annotation.Retryable;
|
||||||
|
import com.x.retry.common.core.model.Result;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -13,8 +17,24 @@ import org.springframework.stereotype.Controller;
|
|||||||
* @author www.byteblogs.com
|
* @author www.byteblogs.com
|
||||||
* @since 2022-03-24
|
* @since 2022-03-24
|
||||||
*/
|
*/
|
||||||
@Controller
|
@RestController
|
||||||
@RequestMapping("/teacher")
|
@RequestMapping("/teacher")
|
||||||
public class TeacherController {
|
public class TeacherController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RestTemplate restTemplate;
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
// @Retryable(scene = "testStatusCode")
|
||||||
|
public Result getTeacher() {
|
||||||
|
Result result = restTemplate.getForObject("http://127.0.0.1:8088/school/id", Result.class);
|
||||||
|
result = restTemplate.getForObject("http://127.0.0.1:8088/school/id", Result.class);
|
||||||
|
result = restTemplate.getForObject("http://127.0.0.1:8088/school/id", Result.class);
|
||||||
|
result = restTemplate.getForObject("http://127.0.0.1:8088/school/id", Result.class);
|
||||||
|
|
||||||
|
if (result.getStatus() == 0) {
|
||||||
|
throw new UnsupportedOperationException(result.getMessage());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ public class RemoteService {
|
|||||||
private RestTemplate restTemplate;
|
private RestTemplate restTemplate;
|
||||||
|
|
||||||
public Result call() {
|
public Result call() {
|
||||||
// restTemplate.getForObject("http://127.0.0.1:8088/school/id", Result.class);
|
return restTemplate.getForObject("http://127.0.0.1:8088/school/id", Result.class);
|
||||||
return new Result();
|
// return new Result();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
pom.xml
@ -21,7 +21,7 @@
|
|||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
<revision>0.0.1.0-SNAPSHOT</revision>
|
<revision>0.0.2.0</revision>
|
||||||
<dingding-talk.version>1.0.0</dingding-talk.version>
|
<dingding-talk.version>1.0.0</dingding-talk.version>
|
||||||
<feign.version>11.7</feign.version>
|
<feign.version>11.7</feign.version>
|
||||||
<hibernate-validator.version>5.4.2.Final</hibernate-validator.version>
|
<hibernate-validator.version>5.4.2.Final</hibernate-validator.version>
|
||||||
|
@ -11,6 +11,7 @@ import com.x.retry.client.core.serializer.JacksonSerializer;
|
|||||||
import com.x.retry.client.core.strategy.RetryStrategy;
|
import com.x.retry.client.core.strategy.RetryStrategy;
|
||||||
import com.x.retry.client.model.DispatchRetryDTO;
|
import com.x.retry.client.model.DispatchRetryDTO;
|
||||||
import com.x.retry.client.model.DispatchRetryResultDTO;
|
import com.x.retry.client.model.DispatchRetryResultDTO;
|
||||||
|
import com.x.retry.common.core.enums.RetryResultStatusEnum;
|
||||||
import com.x.retry.common.core.model.Result;
|
import com.x.retry.common.core.model.Result;
|
||||||
import com.x.retry.common.core.util.JsonUtil;
|
import com.x.retry.common.core.util.JsonUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -58,13 +59,23 @@ public class RetryEndPoint {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
RetryerResultContext retryerResultContext = retryStrategy.openRetry(executeReqDto.getScene(), executeReqDto.getExecutorName(), deSerialize);
|
RetryerResultContext retryerResultContext = retryStrategy.openRetry(executeReqDto.getScene(), executeReqDto.getExecutorName(), deSerialize);
|
||||||
executeRespDto.setStatusCode(retryerResultContext.getRetryResultStatusEnum().getStatus());
|
|
||||||
|
if (RetrySiteSnapshot.isRetryForStatusCode()) {
|
||||||
|
executeRespDto.setStatusCode(RetryResultStatusEnum.STOP.getStatus());
|
||||||
|
|
||||||
|
// TODO 需要标记是哪个系统不需要重试
|
||||||
|
executeRespDto.setExceptionMsg("下游标记不需要重试");
|
||||||
|
} else {
|
||||||
|
executeRespDto.setStatusCode(retryerResultContext.getRetryResultStatusEnum().getStatus());
|
||||||
|
executeRespDto.setExceptionMsg(retryerResultContext.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
executeRespDto.setBizId(executeReqDto.getBizId());
|
executeRespDto.setBizId(executeReqDto.getBizId());
|
||||||
if (Objects.nonNull(retryerResultContext.getResult())) {
|
if (Objects.nonNull(retryerResultContext.getResult())) {
|
||||||
executeRespDto.setResultJson(JsonUtil.toJsonString(retryerResultContext.getResult()));
|
executeRespDto.setResultJson(JsonUtil.toJsonString(retryerResultContext.getResult()));
|
||||||
}
|
}
|
||||||
|
|
||||||
executeRespDto.setExceptionMsg(retryerResultContext.getMessage());
|
|
||||||
} finally {
|
} finally {
|
||||||
RetrySiteSnapshot.removeAll();
|
RetrySiteSnapshot.removeAll();
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
package com.x.retry.client.core.config;
|
|
||||||
|
|
||||||
import com.x.retry.client.core.intercepter.HeadersInterceptor;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author www.byteblogs.com
|
|
||||||
* @date 2022-03-06
|
|
||||||
* @since 2.0
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class XRetryWebMvcConfigurerAdapter implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private HeadersInterceptor headersInterceptor;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
// 注册拦截器
|
|
||||||
registry.addInterceptor(headersInterceptor).addPathPatterns("/retry/**");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.x.retry.client.core.intercepter;
|
||||||
|
|
||||||
|
import com.x.retry.common.core.constant.SystemConstants;
|
||||||
|
import com.x.retry.common.core.log.LogUtils;
|
||||||
|
import com.x.retry.common.core.model.XRetryHeaders;
|
||||||
|
import com.x.retry.common.core.util.JsonUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: shuguang.zhang
|
||||||
|
* @date : 2022-04-18 09:19
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class HeaderAspect {
|
||||||
|
|
||||||
|
@Before(value = "@within(org.springframework.web.bind.annotation.RestController)")
|
||||||
|
public void before(JoinPoint joinPoint){
|
||||||
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
String xRetry = attributes.getRequest().getHeader(SystemConstants.X_RETRY_HEAD_KEY);
|
||||||
|
if (Objects.nonNull(xRetry)) {
|
||||||
|
// 标记进入方法的时间
|
||||||
|
RetrySiteSnapshot.setEntryMethodTime(System.currentTimeMillis());
|
||||||
|
|
||||||
|
LogUtils.info("x-retry 拦截器 xRetry:[{}]", xRetry);
|
||||||
|
RetrySiteSnapshot.setRetryHeader(JsonUtil.parseObject(xRetry, XRetryHeaders.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterReturning(pointcut = "@within(org.springframework.web.bind.annotation.RestController)", returning = "o")
|
||||||
|
public void afterReturning(Object o) {
|
||||||
|
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
HttpServletResponse response = attributes.getResponse();
|
||||||
|
response.addHeader(SystemConstants.X_RETRY_STATUS_CODE_KEY, RetrySiteSnapshot.getRetryStatusCode());
|
||||||
|
|
||||||
|
RetrySiteSnapshot.removeRetryHeader();
|
||||||
|
RetrySiteSnapshot.removeRetryStatusCode();
|
||||||
|
RetrySiteSnapshot.removeEntryMethodTime();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,46 +0,0 @@
|
|||||||
package com.x.retry.client.core.intercepter;
|
|
||||||
|
|
||||||
import com.x.retry.common.core.constant.SystemConstants;
|
|
||||||
import com.x.retry.common.core.log.LogUtils;
|
|
||||||
import com.x.retry.common.core.model.XRetryHeaders;
|
|
||||||
import com.x.retry.common.core.util.JsonUtil;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Author:byteblogs
|
|
||||||
* @Date:2018/09/27 12:52
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class HeadersInterceptor implements HandlerInterceptor {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
|
|
||||||
String xRetry = httpServletRequest.getHeader(SystemConstants.X_RETRY_HEAD);
|
|
||||||
if (Objects.nonNull(xRetry)) {
|
|
||||||
LogUtils.info("x-retry 拦截器 xRetry:[{}]", xRetry);
|
|
||||||
RetrySiteSnapshot.setRetryHeader(JsonUtil.parseObject(xRetry, XRetryHeaders.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postHandle(HttpServletRequest httpServletRequest,
|
|
||||||
HttpServletResponse httpServletResponse,
|
|
||||||
Object o, ModelAndView modelAndView) throws Exception {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(HttpServletRequest httpServletRequest,
|
|
||||||
HttpServletResponse httpServletResponse,
|
|
||||||
Object o, Exception e) throws Exception {
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,7 +17,6 @@ import org.springframework.beans.factory.annotation.Qualifier;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.support.TransactionSynchronization;
|
import org.springframework.transaction.support.TransactionSynchronization;
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -72,7 +71,14 @@ public class RetryAspect {
|
|||||||
|
|
||||||
private void doHandlerRetry(ProceedingJoinPoint point, String traceId, Retryable retryable, String executorClassName, String methodEntrance, Throwable throwable) {
|
private void doHandlerRetry(ProceedingJoinPoint point, String traceId, Retryable retryable, String executorClassName, String methodEntrance, Throwable throwable) {
|
||||||
|
|
||||||
if (!RetrySiteSnapshot.isMethodEntrance(methodEntrance) || RetrySiteSnapshot.isRunning()) {
|
if (!RetrySiteSnapshot.isMethodEntrance(methodEntrance)
|
||||||
|
|| RetrySiteSnapshot.isRunning()
|
||||||
|
|| Objects.isNull(throwable)
|
||||||
|
// 重试流量不开启重试
|
||||||
|
|| RetrySiteSnapshot.isRetryFlow()
|
||||||
|
// 下游响应不重试码,不开启重试
|
||||||
|
|| RetrySiteSnapshot.isRetryForStatusCode()
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,11 +99,8 @@ public class RetryAspect {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openRetry(ProceedingJoinPoint point, String traceId, Retryable retryable, String executorClassName, Throwable throwable) {
|
private void openRetry(ProceedingJoinPoint point, String traceId, Retryable retryable, String executorClassName, Throwable throwable) {
|
||||||
try {
|
try {
|
||||||
if (Objects.isNull(throwable)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RetryerResultContext context = retryStrategy.openRetry(retryable.scene(), executorClassName, point.getArgs());
|
RetryerResultContext context = retryStrategy.openRetry(retryable.scene(), executorClassName, point.getArgs());
|
||||||
if (RetryResultStatusEnum.SUCCESS.getStatus().equals(context.getRetryResultStatusEnum().getStatus())) {
|
if (RetryResultStatusEnum.SUCCESS.getStatus().equals(context.getRetryResultStatusEnum().getStatus())) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.x.retry.client.core.intercepter;
|
package com.x.retry.client.core.intercepter;
|
||||||
|
|
||||||
|
import com.x.retry.common.core.constant.SystemConstants;
|
||||||
import com.x.retry.common.core.model.XRetryHeaders;
|
import com.x.retry.common.core.model.XRetryHeaders;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ -33,12 +34,22 @@ public class RetrySiteSnapshot {
|
|||||||
*/
|
*/
|
||||||
private static final ThreadLocal<XRetryHeaders> RETRY_HEADER = new ThreadLocal<>();
|
private static final ThreadLocal<XRetryHeaders> RETRY_HEADER = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态码
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<String> RETRY_STATUS_CODE = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进入方法入口时间标记
|
||||||
|
*/
|
||||||
|
private static final ThreadLocal<Long> ENTRY_METHOD_TIME = new ThreadLocal<>();
|
||||||
|
|
||||||
public static Integer getStage() {
|
public static Integer getStage() {
|
||||||
return RETRY_STAGE.get();
|
return RETRY_STAGE.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setStage(int stage) {
|
public static void setStage(int stage) {
|
||||||
RETRY_STAGE.set(stage);
|
RETRY_STAGE.set(stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getMethodEntrance() {
|
public static String getMethodEntrance() {
|
||||||
@ -76,7 +87,7 @@ public class RetrySiteSnapshot {
|
|||||||
/**
|
/**
|
||||||
* 是否是重试流量
|
* 是否是重试流量
|
||||||
*/
|
*/
|
||||||
public static boolean isRetryFlow(XRetryHeaders headers) {
|
public static boolean isRetryFlow() {
|
||||||
XRetryHeaders retryHeader = getRetryHeader();
|
XRetryHeaders retryHeader = getRetryHeader();
|
||||||
if (Objects.nonNull(retryHeader)) {
|
if (Objects.nonNull(retryHeader)) {
|
||||||
return retryHeader.isXRetry();
|
return retryHeader.isXRetry();
|
||||||
@ -85,10 +96,47 @@ public class RetrySiteSnapshot {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getRetryStatusCode() {
|
||||||
|
return RETRY_STATUS_CODE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setRetryStatusCode(String statusCode) {
|
||||||
|
RETRY_STATUS_CODE.set(statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isRetryForStatusCode() {
|
||||||
|
return getRetryStatusCode().equals(SystemConstants.X_RETRY_STATUS_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long getEntryMethodTime() {
|
||||||
|
return ENTRY_METHOD_TIME.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setEntryMethodTime(long entryMethodTime) {
|
||||||
|
ENTRY_METHOD_TIME.set(entryMethodTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeEntryMethodTime() {
|
||||||
|
ENTRY_METHOD_TIME.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void removeRetryHeader(){
|
||||||
|
RETRY_HEADER.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeRetryStatusCode(){
|
||||||
|
RETRY_STATUS_CODE.remove();
|
||||||
|
}
|
||||||
|
|
||||||
public static void removeAll() {
|
public static void removeAll() {
|
||||||
|
|
||||||
RETRY_STATUS.remove();
|
RETRY_STATUS.remove();
|
||||||
RETRY_CLASS_METHOD_ENTRANCE.remove();
|
RETRY_CLASS_METHOD_ENTRANCE.remove();
|
||||||
RETRY_STAGE.remove();
|
RETRY_STAGE.remove();
|
||||||
|
RETRY_HEADER.remove();
|
||||||
|
RETRY_STATUS_CODE.remove();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,6 +157,7 @@ public class RetrySiteSnapshot {
|
|||||||
;
|
;
|
||||||
|
|
||||||
private final int stage;
|
private final int stage;
|
||||||
|
|
||||||
EnumStage(int stage) {
|
EnumStage(int stage) {
|
||||||
this.stage = stage;
|
this.stage = stage;
|
||||||
}
|
}
|
||||||
@ -133,6 +182,7 @@ public class RetrySiteSnapshot {
|
|||||||
;
|
;
|
||||||
|
|
||||||
private final int status;
|
private final int status;
|
||||||
|
|
||||||
EnumStatus(int status) {
|
EnumStatus(int status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import com.x.retry.client.core.retryer.RetryerInfo;
|
|||||||
import com.x.retry.client.core.retryer.RetryerResultContext;
|
import com.x.retry.client.core.retryer.RetryerResultContext;
|
||||||
import com.x.retry.common.core.enums.RetryResultStatusEnum;
|
import com.x.retry.common.core.enums.RetryResultStatusEnum;
|
||||||
import com.x.retry.common.core.log.LogUtils;
|
import com.x.retry.common.core.log.LogUtils;
|
||||||
|
import com.x.retry.common.core.model.XRetryHeaders;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -70,6 +71,12 @@ public class LocalRetryStrategies extends AbstractRetryStrategies {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!RetrySiteSnapshot.isRetryForStatusCode()) {
|
||||||
|
resultContext.setRetryResultStatusEnum(RetryResultStatusEnum.FAILURE);
|
||||||
|
resultContext.setMessage("执行重试检验不通过 原因: 下游标志禁止重试");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +113,6 @@ public class LocalRetryStrategies extends AbstractRetryStrategies {
|
|||||||
// 如果是仅仅本地重试或本地_远程模式则先支持重试
|
// 如果是仅仅本地重试或本地_远程模式则先支持重试
|
||||||
case ONLY_LOCAL:
|
case ONLY_LOCAL:
|
||||||
case LOCAL_REMOTE:
|
case LOCAL_REMOTE:
|
||||||
|
|
||||||
return () -> {
|
return () -> {
|
||||||
if (TransactionSynchronizationManager.isActualTransactionActive()) {
|
if (TransactionSynchronizationManager.isActualTransactionActive()) {
|
||||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||||
|
@ -12,7 +12,6 @@ import com.x.retry.common.core.enums.RetryResultStatusEnum;
|
|||||||
import com.x.retry.common.core.log.LogUtils;
|
import com.x.retry.common.core.log.LogUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
@ -7,8 +7,20 @@ package com.x.retry.common.core.constant;
|
|||||||
public class SystemConstants {
|
public class SystemConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求头
|
* 请求头 key
|
||||||
*/
|
*/
|
||||||
public static final String X_RETRY_HEAD = "X-RETRY";
|
public static final String X_RETRY_HEAD_KEY = "X-RETRY";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常重试码 key
|
||||||
|
*/
|
||||||
|
public static final String X_RETRY_STATUS_CODE_KEY = "X-RETRY-STATUS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异常重试码
|
||||||
|
*/
|
||||||
|
public static final String X_RETRY_STATUS_CODE = "519";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package com.x.retry.common.core.model;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* x-retry 请求头信息
|
||||||
|
*
|
||||||
* @author: shuguang.zhang
|
* @author: shuguang.zhang
|
||||||
* @date : 2022-04-16 22:20
|
* @date : 2022-04-16 22:20
|
||||||
*/
|
*/
|
||||||
@ -13,4 +15,14 @@ public class XRetryHeaders {
|
|||||||
* 是否是重试流量
|
* 是否是重试流量
|
||||||
*/
|
*/
|
||||||
private boolean xRetry;
|
private boolean xRetry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试下发的ID
|
||||||
|
*/
|
||||||
|
private String xRetryId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用链超时时间 单位毫秒(ms)
|
||||||
|
*/
|
||||||
|
private long ddl = 60 * 10 * 1000;
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ public class ExecUnitActor extends AbstractActor {
|
|||||||
HttpHeaders requestHeaders = new HttpHeaders();
|
HttpHeaders requestHeaders = new HttpHeaders();
|
||||||
XRetryHeaders xRetryHeaders = new XRetryHeaders();
|
XRetryHeaders xRetryHeaders = new XRetryHeaders();
|
||||||
xRetryHeaders.setXRetry(Boolean.TRUE);
|
xRetryHeaders.setXRetry(Boolean.TRUE);
|
||||||
requestHeaders.add(SystemConstants.X_RETRY_HEAD, JsonUtil.toJsonString(xRetryHeaders));
|
requestHeaders.add(SystemConstants.X_RETRY_HEAD_KEY, JsonUtil.toJsonString(xRetryHeaders));
|
||||||
|
|
||||||
HttpEntity<DispatchRetryDTO> requestEntity = new HttpEntity<>(dispatchRetryDTO, requestHeaders);
|
HttpEntity<DispatchRetryDTO> requestEntity = new HttpEntity<>(dispatchRetryDTO, requestHeaders);
|
||||||
|
|
||||||
|
@ -100,6 +100,7 @@ public class ScanGroupActor extends AbstractActor {
|
|||||||
|
|
||||||
DispatchService.LAST_AT_MAP.put(groupConfig.getGroupName(), list.get(list.size() - 1).getCreateDt());
|
DispatchService.LAST_AT_MAP.put(groupConfig.getGroupName(), list.get(list.size() - 1).getCreateDt());
|
||||||
|
|
||||||
|
|
||||||
for (RetryTask retryTask : list) {
|
for (RetryTask retryTask : list) {
|
||||||
|
|
||||||
retryCountIncrement(retryTask);
|
retryCountIncrement(retryTask);
|
||||||
@ -121,11 +122,6 @@ public class ScanGroupActor extends AbstractActor {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
if (!executor.filter()) {
|
if (!executor.filter()) {
|
||||||
|
|
||||||
// 不触发重试
|
|
||||||
ActorRef actorRef = ActorGenerator.noRetryActor();
|
|
||||||
actorRef.tell(executor, actorRef);
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ public class RetryExecutor<V> {
|
|||||||
|
|
||||||
for (FilterStrategy filterStrategy : filterStrategies) {
|
for (FilterStrategy filterStrategy : filterStrategies) {
|
||||||
if (!filterStrategy.filter(retryContext)) {
|
if (!filterStrategy.filter(retryContext)) {
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,8 @@ public class StopStrategies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Integer statusCode = data.getStatusCode();
|
Integer statusCode = data.getStatusCode();
|
||||||
return RetryResultStatusEnum.SUCCESS.getStatus().equals(RetryResultStatusEnum.getRetryResultStatusEnum(statusCode).getStatus());
|
Integer status = RetryResultStatusEnum.getRetryResultStatusEnum(statusCode).getStatus();
|
||||||
|
return RetryResultStatusEnum.SUCCESS.getStatus().equals(status) || RetryResultStatusEnum.STOP.getStatus().equals(status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|