feat:2.4.0

1. 完成客户端的调整
This commit is contained in:
byteblogs168 2023-09-26 23:23:55 +08:00
parent 8a0a86bb24
commit 0e94f87742
42 changed files with 561 additions and 71 deletions

View File

@ -1,4 +1,4 @@
package com.aizuda.easy.retry.client.common.client;
package com.aizuda.easy.retry.client.common;
/**
* 组件生命周期

View File

@ -1,13 +1,10 @@
package com.aizuda.easy.retry.client.common.client;
package com.aizuda.easy.retry.client.common;
import com.aizuda.easy.retry.client.common.client.annotation.Mapping;
import com.aizuda.easy.retry.client.common.client.netty.RequestMethod;
import com.aizuda.easy.retry.client.common.annotation.Mapping;
import com.aizuda.easy.retry.client.common.netty.RequestMethod;
import com.aizuda.easy.retry.common.core.constant.SystemConstants.HTTP_PATH;
import com.aizuda.easy.retry.common.core.model.NettyResult;
import com.aizuda.easy.retry.common.core.model.Result;
import java.util.List;
/**
* netty 客户端请求类

View File

@ -1,6 +1,6 @@
package com.aizuda.easy.retry.client.common.client.annotation;
package com.aizuda.easy.retry.client.common.annotation;
import com.aizuda.easy.retry.client.common.client.netty.RequestMethod;
import com.aizuda.easy.retry.client.common.netty.RequestMethod;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;

View File

@ -1,4 +1,4 @@
package com.aizuda.easy.retry.client.common.client.config;
package com.aizuda.easy.retry.client.common.config;
import com.aizuda.easy.retry.common.core.context.SpringContext;
import lombok.Data;

View File

@ -1,4 +1,4 @@
package com.aizuda.easy.retry.client.common.client.exception;
package com.aizuda.easy.retry.client.common.exception;
import com.aizuda.easy.retry.common.core.exception.BaseEasyRetryException;

View File

@ -1,4 +1,4 @@
package com.aizuda.easy.retry.client.common.client.exception;
package com.aizuda.easy.retry.client.common.exception;
import com.aizuda.easy.retry.common.core.exception.BaseEasyRetryException;

View File

@ -1,8 +1,8 @@
package com.aizuda.easy.retry.client.common.client.netty;
package com.aizuda.easy.retry.client.common.netty;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.common.config.EasyRetryProperties;
import com.aizuda.easy.retry.common.core.context.SpringContext;
import com.aizuda.easy.retry.common.core.enums.HeadersEnum;
import com.aizuda.easy.retry.common.core.log.LogUtils;
@ -93,7 +93,8 @@ public class NettyChannel {
.set(HeadersEnum.GROUP_NAME.getKey(), EasyRetryProperties.getGroup())
.set(HeadersEnum.CONTEXT_PATH.getKey(), Optional.ofNullable(serverProperties.getServlet().getContextPath()).orElse("/"))
.set(HeadersEnum.HOST_PORT.getKey(), port)
.set(HeadersEnum.VERSION.getKey(), GroupVersionCache.getVersion())
// TODO 待办
// .set(HeadersEnum.VERSION.getKey(), GroupVersionCache.getVersion())
;
//发送数据

View File

@ -1,7 +1,7 @@
package com.aizuda.easy.retry.client.common.client.netty;
package com.aizuda.easy.retry.client.common.netty;
import com.aizuda.easy.retry.client.common.client.proxy.RequestBuilder;
import com.aizuda.easy.retry.client.common.client.NettyClient;
import com.aizuda.easy.retry.client.common.proxy.RequestBuilder;
import com.aizuda.easy.retry.client.common.NettyClient;
import com.aizuda.easy.retry.common.core.constant.SystemConstants.BEAT;
import com.aizuda.easy.retry.common.core.log.LogUtils;
import com.aizuda.easy.retry.common.core.model.NettyResult;
@ -16,8 +16,6 @@ import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import static com.aizuda.easy.retry.common.core.constant.SystemConstants.BEAT.PING;
/**
* netty 客户端处理器
*

View File

@ -1,7 +1,7 @@
package com.aizuda.easy.retry.client.common.client.netty;
package com.aizuda.easy.retry.client.common.netty;
import com.aizuda.easy.retry.client.common.client.Lifecycle;
import com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.common.Lifecycle;
import com.aizuda.easy.retry.client.common.config.EasyRetryProperties;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;

View File

@ -1,4 +1,4 @@
package com.aizuda.easy.retry.client.common.client.netty;
package com.aizuda.easy.retry.client.common.netty;
import com.aizuda.easy.retry.common.core.log.LogUtils;
import com.aizuda.easy.retry.common.core.model.EasyRetryRequest;

View File

@ -1,12 +1,12 @@
package com.aizuda.easy.retry.client.common.client.proxy;
package com.aizuda.easy.retry.client.common.proxy;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Assert;
import com.aizuda.easy.retry.client.common.client.annotation.Mapping;
import com.aizuda.easy.retry.client.common.client.exception.EasyRetryClientException;
import com.aizuda.easy.retry.client.common.client.exception.EasyRetryClientTimeOutException;
import com.aizuda.easy.retry.client.common.client.netty.NettyChannel;
import com.aizuda.easy.retry.client.common.client.netty.RpcContext;
import com.aizuda.easy.retry.client.common.annotation.Mapping;
import com.aizuda.easy.retry.client.common.exception.EasyRetryClientException;
import com.aizuda.easy.retry.client.common.exception.EasyRetryClientTimeOutException;
import com.aizuda.easy.retry.client.common.netty.NettyChannel;
import com.aizuda.easy.retry.client.common.netty.RpcContext;
import com.aizuda.easy.retry.common.core.log.LogUtils;
import com.aizuda.easy.retry.common.core.model.EasyRetryRequest;
import io.netty.handler.codec.http.HttpMethod;

View File

@ -1,6 +1,6 @@
package com.aizuda.easy.retry.client.common.client.proxy;
package com.aizuda.easy.retry.client.common.proxy;
import com.aizuda.easy.retry.client.common.client.exception.EasyRetryClientException;
import com.aizuda.easy.retry.client.common.exception.EasyRetryClientException;
import java.lang.reflect.Proxy;
import java.util.Objects;

View File

@ -2,14 +2,14 @@
"groups": [
{
"name": "easy-retry",
"type": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties",
"sourceType": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties"
"type": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties",
"sourceType": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties"
},
{
"name": "easy-retry.server",
"sourceMethod": "getServer()",
"type": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties$ServerConfig",
"sourceType": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties"
"type": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties$ServerConfig",
"sourceType": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties"
}
],
"properties": [
@ -18,12 +18,12 @@
"type": "java.lang.String",
"defaultValue": "127.0.0.1",
"description": "服务端的地址,若服务端集群部署则此处配置域名",
"sourceType": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties$ServerConfig"
"sourceType": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties$ServerConfig"
},
{
"name": "easy-retry.server.port",
"type": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties.ServerConfig",
"sourceType": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties",
"type": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties.ServerConfig",
"sourceType": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties",
"description": "服务端netty的端口号",
"defaultValue": "1788"
}

View File

@ -1,14 +1,13 @@
package com.aizuda.easy.retry.client.common.client.cache;
package com.aizuda.easy.retry.client.core.cache;
import com.aizuda.easy.retry.client.core.Lifecycle;
import com.aizuda.easy.retry.client.core.client.NettyClient;
import com.aizuda.easy.retry.client.core.client.proxy.RequestBuilder;
import com.aizuda.easy.retry.client.common.Lifecycle;
import com.aizuda.easy.retry.client.common.NettyClient;
import com.aizuda.easy.retry.client.common.proxy.RequestBuilder;
import com.aizuda.easy.retry.common.core.constant.SystemConstants;
import com.aizuda.easy.retry.common.core.log.LogUtils;
import com.aizuda.easy.retry.common.core.model.NettyResult;
import com.aizuda.easy.retry.common.core.util.JsonUtil;
import com.aizuda.easy.retry.server.model.dto.ConfigDTO;
import com.aizuda.easy.retry.server.model.dto.ConfigDTO.Scene;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@ -42,12 +41,12 @@ public class GroupVersionCache implements Lifecycle {
if (Objects.isNull(configDTO)){
return SystemConstants.DEFAULT_DDL;
}
List<Scene> sceneList = configDTO.getSceneList();
List<ConfigDTO.Scene> sceneList = configDTO.getSceneList();
if (CollectionUtils.isEmpty(sceneList)) {
return SystemConstants.DEFAULT_DDL;
}
for (Scene scene : sceneList) {
for (ConfigDTO.Scene scene : sceneList) {
if (scene.getSceneName().equals(sceneName)) {
return scene.getDdl();
}

View File

@ -1,10 +1,10 @@
package com.aizuda.easy.retry.client.core.client;
import com.aizuda.easy.retry.client.common.annotation.Mapping;
import com.aizuda.easy.retry.client.common.netty.RequestMethod;
import com.aizuda.easy.retry.common.core.constant.SystemConstants.HTTP_PATH;
import com.aizuda.easy.retry.common.core.model.NettyResult;
import com.aizuda.easy.retry.common.core.model.Result;
import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;
@ -18,8 +18,8 @@ import java.util.List;
*/
public interface NettyClient {
@Mapping(method = RequestMethod.GET, path = HTTP_PATH.CONFIG)
Result getConfig(Integer version);
// @Mapping(method = RequestMethod.GET, path = HTTP_PATH.CONFIG)
// Result getConfig(Integer version);
@Mapping(method = RequestMethod.POST, path = HTTP_PATH.BATCH_REPORT)
NettyResult reportRetryInfo(List<RetryTaskDTO> list);

View File

@ -1,6 +1,6 @@
package com.aizuda.easy.retry.client.core.init;
import com.aizuda.easy.retry.client.core.Lifecycle;
import com.aizuda.easy.retry.client.common.Lifecycle;
import com.aizuda.easy.retry.common.core.util.EasyRetryVersion;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -1,6 +1,6 @@
package com.aizuda.easy.retry.client.core.init;
import com.aizuda.easy.retry.client.core.Lifecycle;
import com.aizuda.easy.retry.client.common.Lifecycle;
import com.aizuda.easy.retry.common.core.constant.SystemConstants;
import com.aizuda.easy.retry.common.core.util.EasyRetryVersion;
import lombok.extern.slf4j.Slf4j;

View File

@ -2,10 +2,10 @@ package com.aizuda.easy.retry.client.core.intercepter;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.aizuda.easy.retry.client.common.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.annotation.Retryable;
import com.aizuda.easy.retry.client.core.cache.GroupVersionCache;
import com.aizuda.easy.retry.client.core.cache.RetryerInfoCache;
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot.EnumStage;
import com.aizuda.easy.retry.client.core.retryer.RetryerInfo;
import com.aizuda.easy.retry.client.core.retryer.RetryerResultContext;

View File

@ -1,6 +1,6 @@
package com.aizuda.easy.retry.client.core.register;
import com.aizuda.easy.retry.client.core.Lifecycle;
import com.aizuda.easy.retry.client.common.Lifecycle;
import com.aizuda.easy.retry.client.core.Scanner;
import com.aizuda.easy.retry.client.core.cache.RetryerInfoCache;
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;

View File

@ -1,12 +1,12 @@
package com.aizuda.easy.retry.client.core.report;
import cn.hutool.core.lang.Assert;
import com.aizuda.easy.retry.client.common.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.ExpressionEngine;
import com.aizuda.easy.retry.client.core.IdempotentIdGenerate;
import com.aizuda.easy.retry.client.core.Report;
import com.aizuda.easy.retry.client.core.RetryArgSerializer;
import com.aizuda.easy.retry.client.core.cache.RetryerInfoCache;
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot;
import com.aizuda.easy.retry.client.core.loader.EasyRetrySpiLoader;

View File

@ -1,8 +1,7 @@
package com.aizuda.easy.retry.client.core.report;
import com.aizuda.easy.retry.client.core.Lifecycle;
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties.SlidingWindowConfig;
import com.aizuda.easy.retry.client.common.Lifecycle;
import com.aizuda.easy.retry.client.common.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.retryer.RetryerInfo;
import com.aizuda.easy.retry.client.core.window.SlidingWindow;
import com.aizuda.easy.retry.server.model.dto.RetryTaskDTO;
@ -51,7 +50,7 @@ public class AsyncReport extends AbstractReport implements Lifecycle {
@Override
public void start() {
SlidingWindowConfig slidingWindowConfig = easyRetryProperties.getSlidingWindow();
EasyRetryProperties.SlidingWindowConfig slidingWindowConfig = easyRetryProperties.getSlidingWindow();
slidingWindow = SlidingWindow
.Builder

View File

@ -1,11 +1,11 @@
package com.aizuda.easy.retry.client.core.report;
import com.aizuda.easy.retry.client.common.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.common.proxy.RequestBuilder;
import com.aizuda.easy.retry.client.core.RetryExecutor;
import com.aizuda.easy.retry.client.core.RetryExecutorParameter;
import com.aizuda.easy.retry.client.core.cache.GroupVersionCache;
import com.aizuda.easy.retry.client.core.client.NettyClient;
import com.aizuda.easy.retry.client.core.client.proxy.RequestBuilder;
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.executor.GuavaRetryExecutor;
import com.aizuda.easy.retry.common.core.alarm.Alarm;
import com.aizuda.easy.retry.common.core.alarm.AlarmContext;

View File

@ -1,7 +1,7 @@
package com.aizuda.easy.retry.client.core.report;
import com.aizuda.easy.retry.client.common.proxy.RequestBuilder;
import com.aizuda.easy.retry.client.core.client.NettyClient;
import com.aizuda.easy.retry.client.core.client.proxy.RequestBuilder;
import com.aizuda.easy.retry.client.core.retryer.RetryerInfo;
import com.aizuda.easy.retry.common.core.log.LogUtils;
import com.aizuda.easy.retry.common.core.model.NettyResult;

View File

@ -1,9 +1,9 @@
package com.aizuda.easy.retry.client.core.strategy;
import com.aizuda.easy.retry.client.common.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.RetryExecutor;
import com.aizuda.easy.retry.client.core.RetryExecutorParameter;
import com.aizuda.easy.retry.client.core.cache.GroupVersionCache;
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties;
import com.aizuda.easy.retry.client.core.event.EasyRetryListener;
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot;
import com.aizuda.easy.retry.client.core.Report;

View File

@ -2,14 +2,14 @@
"groups": [
{
"name": "easy-retry",
"type": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties",
"sourceType": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties"
"type": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties",
"sourceType": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties"
},
{
"name": "easy-retry.server",
"sourceMethod": "getServer()",
"type": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties$ServerConfig",
"sourceType": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties"
"type": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties$ServerConfig",
"sourceType": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties"
}
],
"properties": [
@ -18,12 +18,12 @@
"type": "java.lang.String",
"defaultValue": "127.0.0.1",
"description": "服务端的地址,若服务端集群部署则此处配置域名",
"sourceType": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties$ServerConfig"
"sourceType": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties$ServerConfig"
},
{
"name": "easy-retry.server.port",
"type": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties.ServerConfig",
"sourceType": "com.aizuda.easy.retry.client.common.client.config.EasyRetryProperties",
"type": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties.ServerConfig",
"sourceType": "com.aizuda.easy.retry.client.common.config.EasyRetryProperties",
"description": "服务端netty的端口号",
"defaultValue": "1788"
}

View File

@ -16,6 +16,40 @@
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<guava.version>32.0.0-jre</guava.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>easy-retry-common-server-api</artifactId>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>easy-retry-common-client-api</artifactId>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>easy-retry-client-common</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,17 @@
package com.aizuda.easy.retry.client.job.core;
import com.aizuda.easy.retry.client.job.core.dto.ExecuteResult;
import java.util.concurrent.Callable;
/**
* job执行者
*
* @author: www.byteblogs.com
* @date : 2023-09-27 09:38
* @since 2.4.0
*/
public interface IJobExecutor extends Callable<ExecuteResult> {
String getName();
}

View File

@ -0,0 +1,9 @@
package com.aizuda.easy.retry.client.job.core;
/**
* @author www.byteblogs.com
* @date 2023-09-27 22:31:59
* @since
*/
public class JobScanner {
}

View File

@ -0,0 +1,15 @@
package com.aizuda.easy.retry.client.job.core;
import com.aizuda.easy.retry.client.job.core.dto.JobExecutorInfo;
import java.util.List;
/**
* @author: www.byteblogs.com
* @date : 2022-02-10 09:13
*/
public interface Scanner {
List<JobExecutorInfo> doScan();
}

View File

@ -0,0 +1,27 @@
package com.aizuda.easy.retry.client.job.core.annotation;
import java.lang.annotation.*;
/**
* job执行者
*
* @author www.byteblogs.com
* @date 2023-09-26 23:19:01
* @since 2.4.0
*/
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface JobExecutor {
/**
* 执行器名称
*/
String name();
/**
* 执行器方法
*/
String method() default "jobExecute";
}

View File

@ -0,0 +1,28 @@
package com.aizuda.easy.retry.client.job.core.cache;
import com.aizuda.easy.retry.client.job.core.dto.JobExecutorInfo;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author: www.byteblogs.com
* @date : 2022-03-03 17:43
*/
public class JobExecutorInfoCache {
private static final ConcurrentHashMap<String, JobExecutorInfo> JOB_EXECUTOR_REPOSITORY = new ConcurrentHashMap<>();
public static void put(JobExecutorInfo jobExecutorInfo) {
JOB_EXECUTOR_REPOSITORY.put(jobExecutorInfo.getExecutorName(), jobExecutorInfo);
}
public static JobExecutorInfo get(String executorName) {
return JOB_EXECUTOR_REPOSITORY.get(executorName);
}
public static boolean isExisted(String executorName) {
return !Objects.nonNull(JOB_EXECUTOR_REPOSITORY.get(executorName));
}
}

View File

@ -0,0 +1,30 @@
package com.aizuda.easy.retry.client.job.core.cache;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
* @author: www.byteblogs.com
* @date : 2023-09-27 17:12
*/
@Component
public class ThreadPoolCache {
private static final ConcurrentHashMap<Long, ThreadPoolExecutor> CACHE_THREAD_POOL = new ConcurrentHashMap<>();
public static ThreadPoolExecutor createThreadPool(Long taskId, int parallelNum) {
Supplier<ThreadPoolExecutor> supplier = () -> new ThreadPoolExecutor(
parallelNum, parallelNum, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>()
);
return CACHE_THREAD_POOL.putIfAbsent(taskId, supplier.get());
}
public static void getThreadPool(Long taskId, int parallelNum) {
}
}

View File

@ -0,0 +1,74 @@
package com.aizuda.easy.retry.client.job.core.client;
import com.aizuda.easy.retry.client.job.core.cache.JobExecutorInfoCache;
import com.aizuda.easy.retry.client.job.core.cache.ThreadPoolCache;
import com.aizuda.easy.retry.client.job.core.dto.ExecuteResult;
import com.aizuda.easy.retry.client.job.core.dto.JobContext;
import com.aizuda.easy.retry.client.job.core.dto.JobExecutorInfo;
import com.aizuda.easy.retry.client.model.DispatchJobDTO;
import com.aizuda.easy.retry.client.model.InterruptJobDTO;
import com.aizuda.easy.retry.common.core.context.SpringContext;
import com.aizuda.easy.retry.common.core.model.Result;
import com.google.common.util.concurrent.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author: www.byteblogs.com
* @date : 2023-09-27 16:33
*/
@RestController
@RequestMapping("/job")
@Slf4j
public class JobEndPoint {
@PostMapping("/dispatch/v1")
public Result<Boolean> dispatchJob(@RequestBody @Validated DispatchJobDTO dispatchJob) {
// 创建可执行的任务
ThreadPoolExecutor threadPool = ThreadPoolCache.createThreadPool(dispatchJob.getTaskId(), dispatchJob.getParallelNum());
ListeningExecutorService decorator = MoreExecutors.listeningDecorator(threadPool);
JobContext jobContext = new JobContext();
jobContext.setJobId(dispatchJob.getJobId());
jobContext.setTaskId(dispatchJob.getTaskId());
jobContext.setGroupName(dispatchJob.getGroupName());
String executorName = dispatchJob.getExecutorName();
JobExecutorInfo jobExecutorInfo = JobExecutorInfoCache.get(executorName);
// 执行任务
ListenableFuture<ExecuteResult> submit = decorator.submit(() -> {
return (ExecuteResult) ReflectionUtils.invokeMethod(jobExecutorInfo.getMethod(), jobExecutorInfo.getExecutor(), jobContext);
});
Futures.addCallback(submit, new FutureCallback<ExecuteResult>() {
@Override
public void onSuccess(ExecuteResult result) {
// 上报执行成功
}
@Override
public void onFailure(Throwable t) {
// 上报执行失败
}
}, threadPool);
return new Result<>(Boolean.TRUE);
}
@PostMapping("/interrupt/v1")
public Result<Boolean> dispatchJob(@RequestBody @Validated InterruptJobDTO interruptJob) {
return new Result<>(Boolean.TRUE);
}
}

View File

@ -0,0 +1,9 @@
package com.aizuda.easy.retry.client.job.core.dto;
/**
* @author: www.byteblogs.com
* @date : 2023-09-27 09:43
*/
public class ExecuteResult {
}

View File

@ -0,0 +1,17 @@
package com.aizuda.easy.retry.client.job.core.dto;
import lombok.Data;
/**
* @author: www.byteblogs.com
* @date : 2023-09-27 09:40
*/
@Data
public class JobContext {
private Long jobId;
private Long taskId;
private String groupName;
}

View File

@ -0,0 +1,22 @@
package com.aizuda.easy.retry.client.job.core.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.lang.reflect.Method;
/**
* @author www.byteblogs.com
* @date 2023-09-27 22:34:29
* @since 2.4.0
*/
@Data
@AllArgsConstructor
public class JobExecutorInfo {
private final String executorName;
private final Method method;
Object executor;
}

View File

@ -0,0 +1,26 @@
package com.aizuda.easy.retry.client.job.core.handler;
import com.aizuda.easy.retry.client.job.core.IJobExecutor;
import com.aizuda.easy.retry.client.job.core.dto.ExecuteResult;
import com.aizuda.easy.retry.client.job.core.dto.JobContext;
/**
* 广播模式
*
* @author: www.byteblogs.com
* @date : 2023-09-27 09:48
* @since 2.4.0
*/
public abstract class AbstractIJobExecutor implements IJobExecutor {
@Override
public ExecuteResult call() throws Exception {
JobContext jobContext = new JobContext();
ExecuteResult executeResult = jobExecute(jobContext);
return executeResult;
}
protected abstract ExecuteResult jobExecute(JobContext jobContext);
}

View File

@ -0,0 +1,17 @@
package com.aizuda.easy.retry.client.job.core.handler;
import com.aizuda.easy.retry.client.job.core.dto.ExecuteResult;
import com.aizuda.easy.retry.client.job.core.dto.JobContext;
/**
* @author www.byteblogs.com
* @date 2023-09-27 22:20:36
* @since 2.4.0
*/
public abstract class SimpleIJobExecutor extends AbstractIJobExecutor {
@Override
public ExecuteResult jobExecute(JobContext jobContext) {
return null;
}
}

View File

@ -0,0 +1,49 @@
package com.aizuda.easy.retry.client.job.core.register;
import com.aizuda.easy.retry.client.common.Lifecycle;
import com.aizuda.easy.retry.client.common.exception.EasyRetryClientException;
import com.aizuda.easy.retry.client.job.core.Scanner;
import com.aizuda.easy.retry.client.job.core.cache.JobExecutorInfoCache;
import com.aizuda.easy.retry.client.job.core.dto.JobExecutorInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
/**
* @author: www.byteblogs.com
* @date : 2022-02-10 09:12
*/
@Component
public class JobExecutorRegistrar implements Lifecycle {
@Autowired
private List<Scanner> scanners;
public void registerRetryHandler(JobExecutorInfo jobExecutorInfo) {
if (JobExecutorInfoCache.isExisted(jobExecutorInfo.getExecutorName())) {
throw new EasyRetryClientException("不允许executorName重复的", jobExecutorInfo.getExecutorName());
}
JobExecutorInfoCache.put(jobExecutorInfo);
}
public void registerRetryHandler(List<JobExecutorInfo> contextList) {
for (JobExecutorInfo jobExecutorInfo : contextList) {
registerRetryHandler(jobExecutorInfo);
}
}
@Override
public void start() {
for (Scanner scanner : scanners) {
this.registerRetryHandler(scanner.doScan());
}
}
@Override
public void close() {
}
}

View File

@ -0,0 +1,112 @@
package com.aizuda.easy.retry.client.job.core.register.scan;
import com.aizuda.easy.retry.client.job.core.IJobExecutor;
import com.aizuda.easy.retry.client.job.core.Scanner;
import com.aizuda.easy.retry.client.job.core.annotation.JobExecutor;
import com.aizuda.easy.retry.client.job.core.cache.JobExecutorInfoCache;
import com.aizuda.easy.retry.client.job.core.dto.JobExecutorInfo;
import com.aizuda.easy.retry.common.core.log.LogUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @author: www.byteblogs.com
* @date : 2023-09-27 16:55
*/
@Component
@Slf4j
public class JobExecutorScanner implements Scanner, ApplicationContextAware {
public ApplicationContext applicationContext;
@Override
public List<JobExecutorInfo> doScan() {
return scanRetryAbleMethod();
}
private List<JobExecutorInfo> scanRetryAbleMethod() {
List<JobExecutorInfo> retryerInfoList = new ArrayList<>();
String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = applicationContext.getBean(beanDefinitionName);
Map<Method, JobExecutor> annotatedMethods = null;
try {
annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
(MethodIntrospector.MetadataLookup<JobExecutor>) method -> AnnotatedElementUtils
.findMergedAnnotation(method, JobExecutor.class));
} catch (Throwable ex) {
LogUtils.error(log, "{} JobExecutor加载异常{}", beanDefinitionName, ex);
}
if (annotatedMethods == null || annotatedMethods.isEmpty()) {
continue;
}
String executorClassName = bean.getClass().getName();
// 通过实现接口进行注册
if (bean.getClass().isAssignableFrom(IJobExecutor.class)) {
IJobExecutor iJobExecutor = (IJobExecutor) bean;
String executorName = iJobExecutor.getName();
if (JobExecutorInfoCache.isExisted(executorName)) {
retryerInfoList.add(new JobExecutorInfo(executorClassName, ReflectionUtils.findMethod(bean.getClass(), "jobExecute"), bean));
}
}
// 扫描类的注解
JobExecutor jobExecutor = bean.getClass().getAnnotation(JobExecutor.class);
if (Objects.nonNull(jobExecutor)) {
String executorName = jobExecutor.name();
if (JobExecutorInfoCache.isExisted(executorName)) {
JobExecutorInfo jobExecutorInfo =
new JobExecutorInfo(
executorName,
ReflectionUtils.findMethod(bean.getClass(), jobExecutor.method()),
bean
);
retryerInfoList.add(jobExecutorInfo);
}
}
// 扫描方法上的注解
for (Map.Entry<Method, JobExecutor> methodEntry : annotatedMethods.entrySet()) {
Method executeMethod = methodEntry.getKey();
jobExecutor = methodEntry.getValue();
if (JobExecutorInfoCache.isExisted(jobExecutor.name())) {
continue;
}
JobExecutorInfo jobExecutorInfo =
new JobExecutorInfo(
jobExecutor.name(),
executeMethod,
bean
);
retryerInfoList.add(jobExecutorInfo);
}
}
return retryerInfoList;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

View File

@ -21,4 +21,14 @@ public class DispatchJobDTO {
@NotBlank(message = "group 不能为空")
private String groupName;
@NotBlank(message = "parallelNum 不能为空")
private Integer parallelNum;
@NotNull(message = "executorType 不能为空")
private Integer executorType;
@NotBlank(message = "executorName 不能为空")
private String executorName;
}