From 071335aa8e150d54ba3c0993d0a69d28f7ec01b8 Mon Sep 17 00:00:00 2001 From: byteblogs168 <598092184@qq.com> Date: Fri, 29 Sep 2023 23:13:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:2.4.0=201.=20=E8=B0=83=E9=80=9A=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E4=B8=8E=E6=9C=8D=E5=8A=A1=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/sql/easy_retry_mysql.sql | 128 +++++++++------- easy-retry-client-starter/pom.xml | 8 + .../EasyRetryClientAutoConfiguration.java | 9 +- .../EasyRetryJobClientAutoConfiguration.java | 23 +++ .../main/resources/META-INF/spring.factories | 3 +- .../easy-retry-client-common/pom.xml | 4 + .../common}/cache/GroupVersionCache.java | 2 +- .../client/common/netty/NettyChannel.java | 4 +- .../client/core/client/RetryEndPoint.java | 2 +- .../intercepter/EasyRetryInterceptor.java | 2 +- .../client/core/report/ReportListener.java | 2 +- .../strategy/AbstractRetryStrategies.java | 2 +- .../core/strategy/LocalRetryStrategies.java | 1 - .../main/resources/META-INF/spring.factories | 0 .../retry/client/job/core/IJobExecutor.java | 10 +- .../retry/client/job/core/JobScanner.java | 9 -- .../client/job/core/cache/FutureCache.java | 40 +++++ .../job/core/cache/JobExecutorInfoCache.java | 5 +- .../job/core/cache/ThreadPoolCache.java | 28 +++- .../client/job/core/client/JobEndPoint.java | 64 ++++---- .../job/core/client/JobNettyClient.java | 22 +++ .../client/job/core/dto/ExecuteResult.java | 9 -- .../retry/client/job/core/dto/JobContext.java | 17 +++ .../client/job/core/dto/JobExecutorInfo.java | 5 +- .../core/executor/AbstractJobExecutor.java | 48 ++++++ .../core/executor/AnnotationJobExecutor.java | 25 +++ .../core/executor/JobExecutorCallable.java | 23 +++ .../executor/JobExecutorFutureCallback.java | 68 +++++++++ .../job/core/executor/NormalJobExecutor.java | 10 ++ .../core/handler/AbstractIJobExecutor.java | 26 ---- .../job/core/handler/SimpleIJobExecutor.java | 17 --- .../register/scan/JobExecutorScanner.java | 24 +-- .../job/core/timer/StopTaskTimerTask.java | 24 +++ .../client/job/core/timer/TimerManager.java | 30 ++++ .../retry/client/model/ExecuteResult.java | 67 +++++++++ .../{InterruptJobDTO.java => StopJobDTO.java} | 2 +- .../DispatchJobRequest.java} | 15 +- .../request/DispatchJobResultRequest.java | 30 ++++ .../easy-retry-common-core/pom.xml | 5 - .../common/core/constant/SystemConstants.java | 4 + .../core/enums/JobOperationReasonEnum.java | 26 ++++ .../core/enums/JobTaskBatchStatusEnum.java | 55 +++++++ .../common/core/enums/JobTaskStatusEnum.java | 50 ++++++ .../core/handler/RestExceptionHandler.java | 7 +- ...nceMapper.java => JobTaskBatchMapper.java} | 8 +- .../persistence/mapper/JobTaskMapper.java | 2 +- .../persistence/po/GroupConfig.java | 2 + .../datasource/persistence/po/Job.java | 10 ++ .../persistence/po/JobLogMessage.java | 13 +- .../datasource/persistence/po/JobTask.java | 47 ++++-- ...JobTaskInstance.java => JobTaskBatch.java} | 44 +++--- .../persistence/po/SceneConfig.java | 2 - .../mysql/mapper/JobTaskBatchMapper.xml | 34 +++++ .../mysql/mapper/JobTaskInstanceMapper.xml | 18 --- .../resources/mysql/mapper/JobTaskMapper.xml | 7 +- .../easy-retry-server-common/pom.xml | 4 + .../server/common/akka/ActorGenerator.java | 40 +++++ .../retry/server/common/client/RpcClient.java | 10 +- .../common/client/RpcClientInvokeHandler.java | 99 +++++++++--- .../common/client/SimpleRetryListener.java | 17 +++ .../common/client/annotation/Mapping.java | 14 ++ .../server/common/dto/PartitionTask.java | 14 ++ .../server/common/dto/RegisterNodeInfo.java | 7 + .../retry/server/common/dto/ScanTask.java | 1 + .../common/handler/ServerNodeBalance.java | 1 - .../server/common}/listener/EndListener.java | 2 +- .../common}/listener/StartListener.java | 2 +- .../server/job/EasyRetryJobTaskStarter.java | 28 ++++ .../retry/server/job/task/BlockStrategy.java | 3 +- .../server/job/task/JobTaskConverter.java | 79 ++++++++++ .../job/task/dispatch/JobExecutorActor.java | 55 +++++++ .../task/dispatch/JobExecutorResultActor.java | 76 ++++++++++ .../server/job/task/dispatch/JobLogActor.java | 61 ++++++++ .../task/dispatch/JobTaskPrepareActor.java | 75 +++++++++ .../job/task/dispatch/ScanJobTaskActor.java | 137 +++++++++++++++++ .../retry/server/job/task/dto/BaseDTO.java | 19 +++ .../job/task/dto/JobExecutorResultDTO.java | 31 ++++ .../retry/server/job/task/dto/JobLogDTO.java | 44 ++++++ .../server/job/task/dto/JobPartitionTask.java | 52 +++++++ .../job/task/dto/JobTaskPrepareDTO.java | 66 ++------ .../server/job/task/dto/JobTimerTaskDTO.java | 14 ++ .../job/task/dto/RealJobExecutorDTO.java | 71 +++++++++ .../job/task/dto/RealStopTaskInstanceDTO.java | 20 +++ .../server/job/task/dto/TaskExecuteDTO.java | 4 +- .../job/task/enums/BlockStrategyEnum.java | 9 -- .../server/job/task/enums/TaskStatusEnum.java | 52 ------- .../server/job/task/enums/TaskTypeEnum.java | 31 ++++ .../server/job/task/executor/JobExecutor.java | 9 -- .../batch/JobTaskBatchGenerator.java | 65 ++++++++ .../batch/JobTaskBatchGeneratorContext.java | 36 +++++ .../task/AbstractJobTaskGenerator.java | 26 ++++ .../task/BroadcastTaskGenerator.java | 73 +++++++++ .../generator/task/ClusterTaskGenerator.java | 69 +++++++++ .../task/JobTaskGenerateContext.java | 15 ++ .../task/generator/task/JobTaskGenerator.java | 19 +++ .../task/JobTaskGeneratorFactory.java | 23 +++ .../generator/task/ShardingTaskGenerator.java | 80 ++++++++++ .../AbstractClientCallbackHandler.java | 25 +++ .../BroadcastClientCallbackHandler.java | 40 +++++ .../callback/ClientCallbackContext.java | 27 ++++ .../callback/ClientCallbackFactory.java | 23 +++ .../callback/ClientCallbackHandler.java | 15 ++ .../ClusterClientCallbackHandler.java | 39 +++++ .../ShardingClientCallbackHandler.java | 40 +++++ .../handler/executor/AbstractJobExecutor.java | 51 +++++++ .../executor/BroadcastTaskJobExecutor.java | 43 ++++++ .../handler/executor/ClusterJobExecutor.java | 42 ++++++ .../task/handler/executor/JobExecutor.java | 15 ++ .../handler/executor/JobExecutorContext.java | 41 +++++ .../handler/executor/JobExecutorFactory.java | 23 +++ .../executor/RealJobExecutorActor.java | 142 ++++++++++++++++++ .../handler/executor/ShardingJobExecutor.java | 44 ++++++ .../handler/helper/JobTaskBatchHelper.java | 53 +++++++ .../prepare/AbstractJobPrePareHandler.java | 19 +++ .../handler/prepare/JobPrePareHandler.java | 15 ++ .../prepare/RunningJobPrepareHandler.java | 62 ++++++++ .../prepare/TerminalJobPrepareHandler.java | 42 ++++++ .../prepare/WaitJobPrepareHandler.java | 48 ++++++ ...tDispatchResultPostHttpRequestHandler.java | 64 ++++++++ .../stop/AbstractJobTaskStopHandler.java | 63 ++++++++ .../stop/BroadcastTaskStopHandler.java | 43 ++++++ .../handler/stop/ClusterTaskStopHandler.java | 51 +++++++ .../task/handler/stop/JobTaskStopFactory.java | 23 +++ .../task/handler/stop/JobTaskStopHandler.java | 16 ++ .../task/handler/stop/RealStopTaskActor.java | 66 ++++++++ .../handler/stop/ShardingTaskStopHandler.java | 40 +++++ .../task/handler/stop/TaskStopJobContext.java | 49 ++++++ .../job/task/handler/timer/JobTimerTask.java | 80 ++++++++++ .../timer}/JobTimerWheelHandler.java | 27 ++-- .../server/job/task/scan/JobContext.java | 15 -- .../job/task/scan/JobExecutorActor.java | 66 -------- .../job/task/scan/JobTaskPrepareActor.java | 98 ------------ .../server/job/task/scan/JobTimerTask.java | 36 ----- .../job/task/scan/ScanJobTaskActor.java | 130 ---------------- .../job/task/strategy/BlockStrategies.java | 101 ++++--------- .../support/schedule/AbstractSchedule.java | 6 +- .../support/schedule/OfflineNodeSchedule.java | 6 +- .../RetryErrorMoreThresholdAlarmSchedule.java | 6 +- .../RetryTaskMoreThresholdAlarmSchedule.java | 6 +- .../support/schedule/RetryTaskSchedule.java | 6 +- .../server/EasyRetryServerApplication.java | 3 - .../server/dispatch/ConsumerBucketActor.java | 36 +++-- .../server/dispatch/DispatchService.java | 2 +- pom.xml | 5 + 144 files changed, 3705 insertions(+), 883 deletions(-) create mode 100644 easy-retry-client-starter/src/main/java/com/aizuda/easy/retry/client/starter/EasyRetryJobClientAutoConfiguration.java rename easy-retry-client/{easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core => easy-retry-client-common/src/main/java/com/aizuda/easy/retry/client/common}/cache/GroupVersionCache.java (98%) delete mode 100644 easy-retry-client/easy-retry-client-core/src/main/resources/META-INF/spring.factories delete mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/JobScanner.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/FutureCache.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/client/JobNettyClient.java delete mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/ExecuteResult.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/AbstractJobExecutor.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/AnnotationJobExecutor.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/JobExecutorCallable.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/JobExecutorFutureCallback.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/NormalJobExecutor.java delete mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/handler/AbstractIJobExecutor.java delete mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/handler/SimpleIJobExecutor.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/timer/StopTaskTimerTask.java create mode 100644 easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/timer/TimerManager.java create mode 100644 easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/ExecuteResult.java rename easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/{InterruptJobDTO.java => StopJobDTO.java} (93%) rename easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/{DispatchJobDTO.java => request/DispatchJobRequest.java} (65%) create mode 100644 easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/request/DispatchJobResultRequest.java create mode 100644 easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobOperationReasonEnum.java create mode 100644 easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobTaskBatchStatusEnum.java create mode 100644 easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobTaskStatusEnum.java rename easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/{JobTaskInstanceMapper.java => JobTaskBatchMapper.java} (54%) rename easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/{JobTaskInstance.java => JobTaskBatch.java} (68%) create mode 100644 easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskBatchMapper.xml delete mode 100644 easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskInstanceMapper.xml create mode 100644 easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/SimpleRetryListener.java create mode 100644 easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/PartitionTask.java rename easy-retry-server/{easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support => easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common}/listener/EndListener.java (92%) rename easy-retry-server/{easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support => easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common}/listener/StartListener.java (95%) create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/EasyRetryJobTaskStarter.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/JobTaskConverter.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobExecutorActor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobExecutorResultActor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobLogActor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobTaskPrepareActor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/ScanJobTaskActor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/BaseDTO.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobExecutorResultDTO.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobLogDTO.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobPartitionTask.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobTimerTaskDTO.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/RealJobExecutorDTO.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/RealStopTaskInstanceDTO.java delete mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/BlockStrategyEnum.java delete mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/TaskStatusEnum.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/TaskTypeEnum.java delete mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/executor/JobExecutor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/batch/JobTaskBatchGenerator.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/batch/JobTaskBatchGeneratorContext.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/AbstractJobTaskGenerator.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/BroadcastTaskGenerator.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/ClusterTaskGenerator.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGenerateContext.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGenerator.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGeneratorFactory.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/ShardingTaskGenerator.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/AbstractClientCallbackHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/BroadcastClientCallbackHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackContext.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackFactory.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClusterClientCallbackHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ShardingClientCallbackHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/AbstractJobExecutor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/BroadcastTaskJobExecutor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/ClusterJobExecutor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutorContext.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutorFactory.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/RealJobExecutorActor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/ShardingJobExecutor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/helper/JobTaskBatchHelper.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/AbstractJobPrePareHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/JobPrePareHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/RunningJobPrepareHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/TerminalJobPrepareHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/WaitJobPrepareHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/request/ReportDispatchResultPostHttpRequestHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/AbstractJobTaskStopHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/BroadcastTaskStopHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/ClusterTaskStopHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/JobTaskStopFactory.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/JobTaskStopHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/RealStopTaskActor.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/ShardingTaskStopHandler.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/TaskStopJobContext.java create mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/timer/JobTimerTask.java rename easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/{scan => handler/timer}/JobTimerWheelHandler.java (73%) delete mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobContext.java delete mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobExecutorActor.java delete mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTaskPrepareActor.java delete mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTimerTask.java delete mode 100644 easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/ScanJobTaskActor.java diff --git a/doc/sql/easy_retry_mysql.sql b/doc/sql/easy_retry_mysql.sql index 975920aa..a64f4f71 100644 --- a/doc/sql/easy_retry_mysql.sql +++ b/doc/sql/easy_retry_mysql.sql @@ -15,6 +15,7 @@ CREATE TABLE `group_config` `route_key` tinyint(4) NOT NULL COMMENT '路由策略', `id_generator_mode` tinyint(4) NOT NULL DEFAULT '1' COMMENT '唯一id生成模式 默认号段模式', `init_scene` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否初始化场景 0:否 1:是', + `bucket_index` int(11) DEFAULT NULL COMMENT 'bucket', `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY (`id`), @@ -134,7 +135,6 @@ CREATE TABLE `scene_config` `back_off` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1、默认等级 2、固定间隔时间 3、CRON 表达式', `trigger_interval` varchar(16) NOT NULL DEFAULT '' COMMENT '间隔时长', `deadline_request` bigint(20) unsigned NOT NULL DEFAULT '60000' COMMENT 'Deadline Request 调用链超时 单位毫秒', - `bucket_index` int(11) DEFAULT NULL COMMENT 'bucket', `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', @@ -215,64 +215,76 @@ CREATE TABLE `sequence_alloc` ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='号段模式序号ID分配表'; -- 分布式调度DDL - CREATE TABLE `job` ( - `id` BIGINT ( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', - `group_name` VARCHAR ( 64 ) NOT NULL COMMENT '组名称', - `job_name` VARCHAR ( 64 ) NOT NULL COMMENT '名称', - `args_str` TEXT NOT NULL COMMENT '执行方法参数', - `args_type` VARCHAR ( 16 ) NOT NULL DEFAULT '' COMMENT '参数类型 text/json', - `ext_attrs` TEXT NOT NULL COMMENT '扩展字段', - `next_trigger_at` DATETIME NOT NULL COMMENT '下次触发时间', - `job_status` TINYINT ( 4 ) NOT NULL DEFAULT '1' COMMENT '重试状态 0、关闭、1、开启', - `route_key` VARCHAR ( 50 ) DEFAULT NULL COMMENT '执行器路由策略', - `executor_type` TINYINT ( 4 ) NOT NULL DEFAULT '1' COMMENT '执行器类型 1、Java', - `executor_name` VARCHAR ( 255 ) DEFAULT NULL COMMENT '执行器名称', - `block_strategy` VARCHAR ( 50 ) DEFAULT NULL COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', - `executor_timeout` INT ( 11 ) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒', - `max_retry_times` INT ( 11 ) NOT NULL DEFAULT '0' COMMENT '最大重试次数', - `retry_interval` INT ( 11 ) NOT NULL DEFAULT '0' COMMENT '重试间隔(s)', + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_name` varchar(64) NOT NULL COMMENT '名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `args_type` varchar(16) NOT NULL DEFAULT '' COMMENT '参数类型 text/json', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `next_trigger_at` datetime NOT NULL COMMENT '下次触发时间', + `job_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '重试状态 0、关闭、1、开启', + `task_type` varchar(255) DEFAULT NULL COMMENT '任务类型 1、集群 2、广播 3、切片', + `route_key` varchar(50) DEFAULT NULL COMMENT '执行器路由策略', + `executor_type` tinyint(4) NOT NULL DEFAULT '1' COMMENT '执行器类型 1、Java', + `executor_name` varchar(255) DEFAULT NULL COMMENT '执行器名称', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `executor_timeout` int(11) NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒', + `max_retry_times` int(11) NOT NULL DEFAULT '0' COMMENT '最大重试次数', + `parallel_num` int(11) NOT NULL DEFAULT '1' COMMENT '并行数', + `retry_interval` int(11) NOT NULL DEFAULT '0' COMMENT '重试间隔(s)', `bucket_index` int(11) NOT NULL DEFAULT '0' COMMENT 'bucket', - `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', - `create_dt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_dt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - `deleted` TINYINT ( 4 ) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', - PRIMARY KEY ( `id` ), - KEY `idx_group_name` ( `group_name` ) - ) ENGINE = INNODB AUTO_INCREMENT = 0 DEFAULT CHARSET = utf8mb4 COMMENT = '任务信息'; - -CREATE TABLE `job_task` ( - `id` BIGINT ( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', - `group_name` VARCHAR ( 64 ) NOT NULL COMMENT '组名称', - `job_id` BIGINT ( 20 ) NOT NULL COMMENT '任务id', - `retry_count` INT ( 11 ) NOT NULL DEFAULT '0' COMMENT '重试次数', - `task_status` TINYINT ( 4 ) NOT NULL DEFAULT '0' COMMENT '任务状态 0、失败 1、成功', - `create_dt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_dt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - `deleted` TINYINT ( 4 ) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', - PRIMARY KEY ( `id` ) - ) ENGINE = INNODB AUTO_INCREMENT = 0 DEFAULT CHARSET = utf8mb4 COMMENT = '调度任务'; - -CREATE TABLE `job_task_instance` ( - `id` BIGINT ( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', - `group_name` VARCHAR ( 64 ) NOT NULL COMMENT '组名称', - `job_id` BIGINT ( 20 ) NOT NULL COMMENT '任务信息id', - `task_id` BIGINT ( 20 ) NOT NULL COMMENT '调度任务id', - `parent_id` BIGINT ( 20 ) NOT NULL DEFAULT '0' COMMENT '父执行器id', - `execute_status` TINYINT ( 4 ) NOT NULL DEFAULT '0' COMMENT '执行的状态 0、失败 1、成功', - `result_message` TEXT NOT NULL COMMENT '执行结果', - `create_dt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_dt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY ( `id` ) - ) ENGINE = INNODB AUTO_INCREMENT = 0 DEFAULT CHARSET = utf8mb4 COMMENT = '任务实例'; + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', + PRIMARY KEY (`id`), + KEY `idx_group_name` (`group_name`) + ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='任务信息'; CREATE TABLE `job_log_message` ( - `id` BIGINT ( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键', - `group_name` VARCHAR ( 64 ) NOT NULL COMMENT '组名称', - `job_id` BIGINT ( 20 ) NOT NULL COMMENT '任务信息id', - `task_id` BIGINT ( 20 ) NOT NULL COMMENT '任务实例id', - `task_instance_id` BIGINT ( 20 ) NOT NULL COMMENT '调度任务id', - `create_dt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `message` TEXT NOT NULL COMMENT '调度信息', - PRIMARY KEY ( `id` ) - ) ENGINE = INNODB AUTO_INCREMENT = 0 DEFAULT CHARSET = utf8mb4 COMMENT = '调度日志'; \ No newline at end of file + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '任务批次id', + `task_id` bigint(20) NOT NULL COMMENT '调度任务id', + `client_address` varchar(255) DEFAULT NULL COMMENT '客户端地址', + `message` text NOT NULL COMMENT '调度信息', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + PRIMARY KEY (`id`) + ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='调度日志'; + +CREATE TABLE `job_task` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '调度任务id', + `parent_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '父执行器id', + `execute_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行的状态 0、失败 1、成功', + `retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '重试次数', + `client_id` varchar(255) DEFAULT NULL COMMENT '客户端地址', + `result_message` text NOT NULL COMMENT '执行结果', + `args_str` text NOT NULL COMMENT '执行方法参数', + `args_type` varchar(16) NOT NULL DEFAULT '' COMMENT '参数类型 text/json', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`) + ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='任务实例'; + +CREATE TABLE `job_task_batch` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务id', + `task_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '任务状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT '0' COMMENT '操作原因', + `execution_at` datetime DEFAULT NULL COMMENT '任务执行时间', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + `deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1、删除', + `ext_attrs` varchar(256) NULL default '' COMMENT '扩展字段', + PRIMARY KEY (`id`) + ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='任务批次'; diff --git a/easy-retry-client-starter/pom.xml b/easy-retry-client-starter/pom.xml index 33139eb1..0de8814a 100644 --- a/easy-retry-client-starter/pom.xml +++ b/easy-retry-client-starter/pom.xml @@ -26,6 +26,14 @@ com.aizuda easy-retry-client-core + provided + true + + + com.aizuda + easy-retry-client-job-core + provided + true org.springframework diff --git a/easy-retry-client-starter/src/main/java/com/aizuda/easy/retry/client/starter/EasyRetryClientAutoConfiguration.java b/easy-retry-client-starter/src/main/java/com/aizuda/easy/retry/client/starter/EasyRetryClientAutoConfiguration.java index 1be08543..a02e2bd8 100644 --- a/easy-retry-client-starter/src/main/java/com/aizuda/easy/retry/client/starter/EasyRetryClientAutoConfiguration.java +++ b/easy-retry-client-starter/src/main/java/com/aizuda/easy/retry/client/starter/EasyRetryClientAutoConfiguration.java @@ -1,11 +1,13 @@ package com.aizuda.easy.retry.client.starter; +import com.aizuda.easy.retry.client.core.annotation.Retryable; import com.aizuda.easy.retry.client.core.intercepter.EasyRetryInterceptor; import com.aizuda.easy.retry.client.core.intercepter.EasyRetryPointcutAdvisor; import com.aizuda.easy.retry.client.core.strategy.RetryStrategy; import org.aopalliance.intercept.MethodInterceptor; import org.springframework.aop.Advisor; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -16,20 +18,21 @@ import org.springframework.core.env.StandardEnvironment; @Configuration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) -@ComponentScan("com.aizuda.easy.retry.client.core") +@ConditionalOnClass(Retryable.class) +@ComponentScan({"com.aizuda.easy.retry.client.core", "com.aizuda.easy.retry.client.common"}) @ConditionalOnProperty(prefix = "easy-retry", name = "enabled", havingValue = "true") public class EasyRetryClientAutoConfiguration { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) - public Advisor easyRetryPointcutAdvisor (MethodInterceptor easyRetryInterceptor) { + public Advisor easyRetryPointcutAdvisor(MethodInterceptor easyRetryInterceptor) { return new EasyRetryPointcutAdvisor(easyRetryInterceptor); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public MethodInterceptor easyRetryInterceptor(StandardEnvironment standardEnvironment, - @Lazy RetryStrategy localRetryStrategies) { + @Lazy RetryStrategy localRetryStrategies) { return new EasyRetryInterceptor(standardEnvironment, localRetryStrategies); } diff --git a/easy-retry-client-starter/src/main/java/com/aizuda/easy/retry/client/starter/EasyRetryJobClientAutoConfiguration.java b/easy-retry-client-starter/src/main/java/com/aizuda/easy/retry/client/starter/EasyRetryJobClientAutoConfiguration.java new file mode 100644 index 00000000..f50323c6 --- /dev/null +++ b/easy-retry-client-starter/src/main/java/com/aizuda/easy/retry/client/starter/EasyRetryJobClientAutoConfiguration.java @@ -0,0 +1,23 @@ +package com.aizuda.easy.retry.client.starter; + +import com.aizuda.easy.retry.client.core.annotation.Retryable; +import com.aizuda.easy.retry.client.core.intercepter.EasyRetryInterceptor; +import com.aizuda.easy.retry.client.core.intercepter.EasyRetryPointcutAdvisor; +import com.aizuda.easy.retry.client.core.strategy.RetryStrategy; +import com.aizuda.easy.retry.client.job.core.annotation.JobExecutor; +import org.aopalliance.intercept.MethodInterceptor; +import org.springframework.aop.Advisor; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.*; +import org.springframework.core.env.StandardEnvironment; + +@Configuration +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +@ComponentScan({"com.aizuda.easy.retry.client.job.core", "com.aizuda.easy.retry.client.common"}) +@ConditionalOnClass(JobExecutor.class) +@ConditionalOnProperty(prefix = "easy-retry", name = "enabled", havingValue = "true") +public class EasyRetryJobClientAutoConfiguration { + +} diff --git a/easy-retry-client-starter/src/main/resources/META-INF/spring.factories b/easy-retry-client-starter/src/main/resources/META-INF/spring.factories index b65e43ff..c47bd83d 100644 --- a/easy-retry-client-starter/src/main/resources/META-INF/spring.factories +++ b/easy-retry-client-starter/src/main/resources/META-INF/spring.factories @@ -1,2 +1,3 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - com.aizuda.easy.retry.client.starter.EasyRetryClientAutoConfiguration + com.aizuda.easy.retry.client.starter.EasyRetryClientAutoConfiguration,\ + com.aizuda.easy.retry.client.starter.EasyRetryJobClientAutoConfiguration diff --git a/easy-retry-client/easy-retry-client-common/pom.xml b/easy-retry-client/easy-retry-client-common/pom.xml index c6225214..48def0bc 100644 --- a/easy-retry-client/easy-retry-client-common/pom.xml +++ b/easy-retry-client/easy-retry-client-common/pom.xml @@ -37,6 +37,10 @@ com.aizuda easy-retry-common-core + + com.aizuda + easy-retry-common-server-api + diff --git a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/cache/GroupVersionCache.java b/easy-retry-client/easy-retry-client-common/src/main/java/com/aizuda/easy/retry/client/common/cache/GroupVersionCache.java similarity index 98% rename from easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/cache/GroupVersionCache.java rename to easy-retry-client/easy-retry-client-common/src/main/java/com/aizuda/easy/retry/client/common/cache/GroupVersionCache.java index 5afdb67b..64601621 100644 --- a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/cache/GroupVersionCache.java +++ b/easy-retry-client/easy-retry-client-common/src/main/java/com/aizuda/easy/retry/client/common/cache/GroupVersionCache.java @@ -1,4 +1,4 @@ -package com.aizuda.easy.retry.client.core.cache; +package com.aizuda.easy.retry.client.common.cache; import com.aizuda.easy.retry.client.common.Lifecycle; import com.aizuda.easy.retry.client.common.NettyClient; diff --git a/easy-retry-client/easy-retry-client-common/src/main/java/com/aizuda/easy/retry/client/common/netty/NettyChannel.java b/easy-retry-client/easy-retry-client-common/src/main/java/com/aizuda/easy/retry/client/common/netty/NettyChannel.java index 309ff9e4..73119a7d 100644 --- a/easy-retry-client/easy-retry-client-common/src/main/java/com/aizuda/easy/retry/client/common/netty/NettyChannel.java +++ b/easy-retry-client/easy-retry-client-common/src/main/java/com/aizuda/easy/retry/client/common/netty/NettyChannel.java @@ -2,6 +2,7 @@ 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.cache.GroupVersionCache; 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; @@ -93,8 +94,7 @@ 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) - // TODO 待办 -// .set(HeadersEnum.VERSION.getKey(), GroupVersionCache.getVersion()) + .set(HeadersEnum.VERSION.getKey(), GroupVersionCache.getVersion()) ; //发送数据 diff --git a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/RetryEndPoint.java b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/RetryEndPoint.java index d2f50c7c..1ed6c771 100644 --- a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/RetryEndPoint.java +++ b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/client/RetryEndPoint.java @@ -3,7 +3,7 @@ package com.aizuda.easy.retry.client.core.client; import cn.hutool.core.lang.Assert; import com.aizuda.easy.retry.client.core.IdempotentIdGenerate; import com.aizuda.easy.retry.client.core.RetryArgSerializer; -import com.aizuda.easy.retry.client.core.cache.GroupVersionCache; +import com.aizuda.easy.retry.client.common.cache.GroupVersionCache; import com.aizuda.easy.retry.client.core.cache.RetryerInfoCache; import com.aizuda.easy.retry.client.core.callback.RetryCompleteCallback; import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException; diff --git a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/intercepter/EasyRetryInterceptor.java b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/intercepter/EasyRetryInterceptor.java index ccecf105..c5f18272 100644 --- a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/intercepter/EasyRetryInterceptor.java +++ b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/intercepter/EasyRetryInterceptor.java @@ -4,7 +4,7 @@ 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.common.cache.GroupVersionCache; import com.aizuda.easy.retry.client.core.cache.RetryerInfoCache; import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot.EnumStage; import com.aizuda.easy.retry.client.core.retryer.RetryerInfo; diff --git a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/report/ReportListener.java b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/report/ReportListener.java index 59f3fa23..6558cb2e 100644 --- a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/report/ReportListener.java +++ b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/report/ReportListener.java @@ -4,7 +4,7 @@ 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.common.cache.GroupVersionCache; import com.aizuda.easy.retry.client.core.client.NettyClient; import com.aizuda.easy.retry.client.core.executor.GuavaRetryExecutor; import com.aizuda.easy.retry.common.core.alarm.Alarm; diff --git a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/AbstractRetryStrategies.java b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/AbstractRetryStrategies.java index b2c474a5..bde32ff9 100644 --- a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/AbstractRetryStrategies.java +++ b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/AbstractRetryStrategies.java @@ -3,7 +3,7 @@ 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.common.cache.GroupVersionCache; 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; diff --git a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/LocalRetryStrategies.java b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/LocalRetryStrategies.java index fa39d78a..bb2cdf6f 100644 --- a/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/LocalRetryStrategies.java +++ b/easy-retry-client/easy-retry-client-core/src/main/java/com/aizuda/easy/retry/client/core/strategy/LocalRetryStrategies.java @@ -2,7 +2,6 @@ package com.aizuda.easy.retry.client.core.strategy; 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.exception.EasyRetryClientException; import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot; import com.aizuda.easy.retry.client.core.retryer.RetryType; diff --git a/easy-retry-client/easy-retry-client-core/src/main/resources/META-INF/spring.factories b/easy-retry-client/easy-retry-client-core/src/main/resources/META-INF/spring.factories deleted file mode 100644 index e69de29b..00000000 diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/IJobExecutor.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/IJobExecutor.java index b0bd9a0d..81726a3a 100644 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/IJobExecutor.java +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/IJobExecutor.java @@ -1,8 +1,7 @@ package com.aizuda.easy.retry.client.job.core; -import com.aizuda.easy.retry.client.job.core.dto.ExecuteResult; - -import java.util.concurrent.Callable; +import com.aizuda.easy.retry.client.model.ExecuteResult; +import com.aizuda.easy.retry.client.job.core.dto.JobContext; /** * job执行者 @@ -11,7 +10,6 @@ import java.util.concurrent.Callable; * @date : 2023-09-27 09:38 * @since 2.4.0 */ -public interface IJobExecutor extends Callable { - - String getName(); +public interface IJobExecutor { + void jobExecute(JobContext jobContext); } diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/JobScanner.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/JobScanner.java deleted file mode 100644 index ac6416ca..00000000 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/JobScanner.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.aizuda.easy.retry.client.job.core; - -/** - * @author www.byteblogs.com - * @date 2023-09-27 22:31:59 - * @since - */ -public class JobScanner { -} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/FutureCache.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/FutureCache.java new file mode 100644 index 00000000..5c42014c --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/FutureCache.java @@ -0,0 +1,40 @@ +package com.aizuda.easy.retry.client.job.core.cache; + +import com.aizuda.easy.retry.client.job.core.dto.JobExecutorInfo; +import com.aizuda.easy.retry.client.model.ExecuteResult; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.google.common.collect.Tables; +import com.google.common.util.concurrent.ListenableFuture; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author www.byteblogs.com + * @date 2023-10-08 23:03:53 + * @since 2.4.0 + */ +public class FutureCache { + + private static final Table> futureCache = HashBasedTable.create(); + + public static void addFuture(Long taskBatchId, Long taskId, ListenableFuture future) { + futureCache.put(taskBatchId, taskId, future); + } + + public static void remove(Long taskBatchId, Long taskId) { + ListenableFuture future = futureCache.get(taskBatchId, taskId); + future.cancel(true); + futureCache.remove(taskBatchId, taskId); + } + + public static void remove(Long taskBatchId) { + Map> futureMap = futureCache.row(taskBatchId); + futureMap.forEach((taskId, future) -> { + future.cancel(true); + futureCache.remove(taskBatchId, taskId); + }); + } + +} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/JobExecutorInfoCache.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/JobExecutorInfoCache.java index b1e6867e..d1cd4422 100644 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/JobExecutorInfoCache.java +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/JobExecutorInfoCache.java @@ -8,9 +8,12 @@ import java.util.concurrent.ConcurrentHashMap; /** * @author: www.byteblogs.com * @date : 2022-03-03 17:43 + * @since : 2.4.0 */ public class JobExecutorInfoCache { + private JobExecutorInfoCache() {} + private static final ConcurrentHashMap JOB_EXECUTOR_REPOSITORY = new ConcurrentHashMap<>(); public static void put(JobExecutorInfo jobExecutorInfo) { @@ -22,7 +25,7 @@ public class JobExecutorInfoCache { } public static boolean isExisted(String executorName) { - return !Objects.nonNull(JOB_EXECUTOR_REPOSITORY.get(executorName)); + return Objects.nonNull(JOB_EXECUTOR_REPOSITORY.get(executorName)); } } diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/ThreadPoolCache.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/ThreadPoolCache.java index 4d2b18a0..fa539110 100644 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/ThreadPoolCache.java +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/cache/ThreadPoolCache.java @@ -9,22 +9,38 @@ import java.util.concurrent.TimeUnit; import java.util.function.Supplier; /** + * TODO 任务执行完成了,该如何优雅的终止线程池????? + * * @author: www.byteblogs.com * @date : 2023-09-27 17:12 + * @since : 2.4.0 */ @Component public class ThreadPoolCache { private static final ConcurrentHashMap CACHE_THREAD_POOL = new ConcurrentHashMap<>(); - public static ThreadPoolExecutor createThreadPool(Long taskId, int parallelNum) { - Supplier supplier = () -> new ThreadPoolExecutor( - parallelNum, parallelNum, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>() - ); - return CACHE_THREAD_POOL.putIfAbsent(taskId, supplier.get()); + public static ThreadPoolExecutor createThreadPool(Long taskBatchId, int parallelNum) { + Supplier supplier = () -> { + + ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( + parallelNum, parallelNum, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); + threadPoolExecutor.allowCoreThreadTimeOut(true); + return threadPoolExecutor; + }; + + ThreadPoolExecutor threadPoolExecutor = supplier.get(); + CACHE_THREAD_POOL.putIfAbsent(taskBatchId, supplier.get()); + return threadPoolExecutor; } - public static void getThreadPool(Long taskId, int parallelNum) { + public static ThreadPoolExecutor getThreadPool(Long taskBatchId) { + return CACHE_THREAD_POOL.get(taskBatchId); + } + public static void stopThreadPool(Long taskBatchId) { + FutureCache.remove(taskBatchId); + ThreadPoolExecutor threadPoolExecutor = CACHE_THREAD_POOL.get(taskBatchId); + threadPoolExecutor.shutdownNow(); } } diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/client/JobEndPoint.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/client/JobEndPoint.java index bbeb60c3..ef616f2f 100644 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/client/JobEndPoint.java +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/client/JobEndPoint.java @@ -1,24 +1,24 @@ package com.aizuda.easy.retry.client.job.core.client; +import com.aizuda.easy.retry.client.job.core.IJobExecutor; 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.executor.AnnotationJobExecutor; +import com.aizuda.easy.retry.client.job.core.executor.NormalJobExecutor; 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.client.model.request.DispatchJobRequest; +import com.aizuda.easy.retry.client.model.StopJobDTO; 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.Objects; import java.util.concurrent.ThreadPoolExecutor; /** @@ -29,46 +29,40 @@ import java.util.concurrent.ThreadPoolExecutor; @RequestMapping("/job") @Slf4j public class JobEndPoint { + @PostMapping("/dispatch/v1") - public Result dispatchJob(@RequestBody @Validated DispatchJobDTO dispatchJob) { - - // 创建可执行的任务 - ThreadPoolExecutor threadPool = ThreadPoolCache.createThreadPool(dispatchJob.getTaskId(), dispatchJob.getParallelNum()); - - ListeningExecutorService decorator = MoreExecutors.listeningDecorator(threadPool); + public Result dispatchJob(@RequestBody @Validated DispatchJobRequest dispatchJob) { JobContext jobContext = new JobContext(); jobContext.setJobId(dispatchJob.getJobId()); jobContext.setTaskId(dispatchJob.getTaskId()); + jobContext.setTaskBatchId(dispatchJob.getTaskBatchId()); jobContext.setGroupName(dispatchJob.getGroupName()); + jobContext.setExecutorName(dispatchJob.getExecutorName()); + jobContext.setParallelNum(dispatchJob.getParallelNum()); + jobContext.setTaskType(dispatchJob.getTaskType()); + jobContext.setExecutorTimeout(dispatchJob.getExecutorTimeout()); - String executorName = dispatchJob.getExecutorName(); - JobExecutorInfo jobExecutorInfo = JobExecutorInfoCache.get(executorName); - - // 执行任务 - ListenableFuture submit = decorator.submit(() -> { - return (ExecuteResult) ReflectionUtils.invokeMethod(jobExecutorInfo.getMethod(), jobExecutorInfo.getExecutor(), jobContext); - }); - - Futures.addCallback(submit, new FutureCallback() { - @Override - public void onSuccess(ExecuteResult result) { - // 上报执行成功 - } - - @Override - public void onFailure(Throwable t) { - // 上报执行失败 - } - }, threadPool); - + JobExecutorInfo jobExecutorInfo = JobExecutorInfoCache.get(jobContext.getExecutorName()); + if (jobExecutorInfo.isAnnotation()) { + IJobExecutor iJobExecutor = SpringContext.getBeanByType(AnnotationJobExecutor.class); + iJobExecutor.jobExecute(jobContext); + } else { + NormalJobExecutor normalJobExecutor = (NormalJobExecutor) jobExecutorInfo.getExecutor(); + normalJobExecutor.jobExecute(jobContext); + } return new Result<>(Boolean.TRUE); } - @PostMapping("/interrupt/v1") - public Result dispatchJob(@RequestBody @Validated InterruptJobDTO interruptJob) { + @PostMapping("/stop/v1") + public Result stopJob(@RequestBody @Validated StopJobDTO interruptJob) { + ThreadPoolExecutor threadPool = ThreadPoolCache.getThreadPool(interruptJob.getTaskId()); + if (Objects.isNull(threadPool) || threadPool.isShutdown() || threadPool.isTerminated()) { + return new Result<>(Boolean.TRUE); + } - return new Result<>(Boolean.TRUE); + ThreadPoolCache.stopThreadPool(interruptJob.getTaskId()); + return new Result<>(threadPool.isShutdown() || threadPool.isTerminated()); } } diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/client/JobNettyClient.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/client/JobNettyClient.java new file mode 100644 index 00000000..f1b39bc0 --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/client/JobNettyClient.java @@ -0,0 +1,22 @@ +package com.aizuda.easy.retry.client.job.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.client.model.request.DispatchJobRequest; +import com.aizuda.easy.retry.client.model.request.DispatchJobResultRequest; +import com.aizuda.easy.retry.common.core.constant.SystemConstants.HTTP_PATH; +import com.aizuda.easy.retry.common.core.model.Result; + +/** + * netty 客户端请求类 + * + * @author: www.byteblogs.com + * @date : 2023-05-11 21:28 + * @since 2.4.0 + */ +public interface JobNettyClient { + + @Mapping(method = RequestMethod.POST, path = HTTP_PATH.REPORT_JOB_DISPATCH_RESULT) + Result dispatchResult(DispatchJobResultRequest request); + +} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/ExecuteResult.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/ExecuteResult.java deleted file mode 100644 index 14f18907..00000000 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/ExecuteResult.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.aizuda.easy.retry.client.job.core.dto; - -/** - * @author: www.byteblogs.com - * @date : 2023-09-27 09:43 - */ -public class ExecuteResult { - -} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/JobContext.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/JobContext.java index 0e7a24a0..ad0b69db 100644 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/JobContext.java +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/JobContext.java @@ -11,7 +11,24 @@ public class JobContext { private Long jobId; + private Long taskBatchId; + private Long taskId; private String groupName; + + private String executorName; + + /** + * 任务类型 + */ + private Integer taskType; + + private Integer parallelNum; + + private Integer shardingTotal; + + private Integer shardingIndex; + + private Integer executorTimeout; } diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/JobExecutorInfo.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/JobExecutorInfo.java index b04b1bba..058b5a11 100644 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/JobExecutorInfo.java +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/dto/JobExecutorInfo.java @@ -18,5 +18,8 @@ public class JobExecutorInfo { private final Method method; - Object executor; + private Object executor; + + private boolean isAnnotation; + } diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/AbstractJobExecutor.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/AbstractJobExecutor.java new file mode 100644 index 00000000..ca1ba266 --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/AbstractJobExecutor.java @@ -0,0 +1,48 @@ +package com.aizuda.easy.retry.client.job.core.executor; + +import com.aizuda.easy.retry.client.job.core.IJobExecutor; +import com.aizuda.easy.retry.client.job.core.cache.FutureCache; +import com.aizuda.easy.retry.client.job.core.cache.ThreadPoolCache; +import com.aizuda.easy.retry.client.job.core.dto.JobContext; +import com.aizuda.easy.retry.client.job.core.timer.StopTaskTimerTask; +import com.aizuda.easy.retry.client.job.core.timer.TimerManager; +import com.aizuda.easy.retry.client.model.ExecuteResult; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +import java.util.concurrent.Callable; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 广播模式 + * + * @author: www.byteblogs.com + * @date : 2023-09-27 09:48 + * @since 2.4.0 + */ +abstract class AbstractJobExecutor implements IJobExecutor { + + @Override + public void jobExecute(JobContext jobContext) { + + // 创建可执行的任务 + ThreadPoolExecutor threadPool = ThreadPoolCache.createThreadPool(jobContext.getTaskBatchId(), jobContext.getParallelNum()); + ListeningExecutorService decorator = MoreExecutors.listeningDecorator(threadPool); + + // 将任务添加到时间轮中,到期停止任务 + TimerManager.add(new StopTaskTimerTask(jobContext.getTaskBatchId()), jobContext.getExecutorTimeout(), TimeUnit.SECONDS); + + // 执行任务 + ListenableFuture submit = decorator.submit(() -> doJobExecute(jobContext)); + + FutureCache.addFuture(jobContext.getTaskBatchId(), jobContext.getTaskId(), submit); + Futures.addCallback(submit, new JobExecutorFutureCallback(jobContext), decorator); + + } + + protected abstract ExecuteResult doJobExecute(JobContext jobContext); + +} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/AnnotationJobExecutor.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/AnnotationJobExecutor.java new file mode 100644 index 00000000..410290b8 --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/AnnotationJobExecutor.java @@ -0,0 +1,25 @@ +package com.aizuda.easy.retry.client.job.core.executor; + +import com.aizuda.easy.retry.client.job.core.cache.JobExecutorInfoCache; +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.ExecuteResult; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; + +/** + * 基于注解的执行器 + * + * @author www.byteblogs.com + * @date 2023-09-27 22:20:36 + * @since 2.4.0 + */ +@Component +public class AnnotationJobExecutor extends AbstractJobExecutor { + + @Override + protected ExecuteResult doJobExecute(final JobContext jobContext) { + JobExecutorInfo jobExecutorInfo = JobExecutorInfoCache.get(jobContext.getExecutorName()); + return (ExecuteResult) ReflectionUtils.invokeMethod(jobExecutorInfo.getMethod(), jobExecutorInfo.getExecutor(), jobContext); + } +} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/JobExecutorCallable.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/JobExecutorCallable.java new file mode 100644 index 00000000..8ff02872 --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/JobExecutorCallable.java @@ -0,0 +1,23 @@ +package com.aizuda.easy.retry.client.job.core.executor; + +import com.aizuda.easy.retry.client.model.ExecuteResult; + +import java.util.concurrent.Callable; + +/** + * @author www.byteblogs.com + * @date 2023-10-08 22:48:44 + * @since 2.4.0 + */ +public class JobExecutorCallable implements Callable { + + public JobExecutorCallable(ExecuteResult executeResult) { + + } + + @Override + public ExecuteResult call() throws Exception { + + return null; + } +} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/JobExecutorFutureCallback.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/JobExecutorFutureCallback.java new file mode 100644 index 00000000..089830b6 --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/JobExecutorFutureCallback.java @@ -0,0 +1,68 @@ +package com.aizuda.easy.retry.client.job.core.executor; + +import com.aizuda.easy.retry.client.common.proxy.RequestBuilder; +import com.aizuda.easy.retry.client.job.core.client.JobNettyClient; +import com.aizuda.easy.retry.client.job.core.dto.JobContext; +import com.aizuda.easy.retry.client.model.ExecuteResult; +import com.aizuda.easy.retry.client.model.request.DispatchJobResultRequest; +import com.aizuda.easy.retry.common.core.enums.JobTaskStatusEnum; +import com.aizuda.easy.retry.common.core.enums.StatusEnum; +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.google.common.util.concurrent.FutureCallback; +import lombok.extern.slf4j.Slf4j; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-08 16:44 + * @since : 2.4.0 + */ +@Slf4j +public class JobExecutorFutureCallback implements FutureCallback { + + private static final JobNettyClient CLIENT = RequestBuilder.newBuilder() + .client(JobNettyClient.class) + .callback(nettyResult -> LogUtils.info(log, "Data report successfully requestId:[{}]", nettyResult.getRequestId())).build(); + + private JobContext jobContext; + + public JobExecutorFutureCallback(final JobContext jobContext) { + this.jobContext = jobContext; + } + + @Override + public void onSuccess(final ExecuteResult result) { + // 上报执行成功 + log.info("任务执行成功 [{}]", JsonUtil.toJsonString(result)); + DispatchJobResultRequest dispatchJobRequest = new DispatchJobResultRequest(); + if (result.getStatus() == StatusEnum.NO.getStatus()) { + dispatchJobRequest.setTaskStatus(JobTaskStatusEnum.FAIL.getStatus()); + } else { + dispatchJobRequest.setTaskStatus(JobTaskStatusEnum.SUCCESS.getStatus()); + } + + dispatchJobRequest.setTaskBatchId(jobContext.getTaskId()); + dispatchJobRequest.setGroupName(jobContext.getGroupName()); + dispatchJobRequest.setJobId(jobContext.getJobId()); + dispatchJobRequest.setTaskId(jobContext.getTaskId()); + dispatchJobRequest.setTaskType(jobContext.getTaskType()); + dispatchJobRequest.setExecuteResult(result); + CLIENT.dispatchResult(dispatchJobRequest); + } + + @Override + public void onFailure(final Throwable t) { + // 上报执行失败 + log.error("任务执行失败 jobTask:[{}]", jobContext.getTaskId(), t); + DispatchJobResultRequest dispatchJobRequest = new DispatchJobResultRequest(); + dispatchJobRequest.setTaskBatchId(jobContext.getTaskId()); + dispatchJobRequest.setGroupName(jobContext.getGroupName()); + dispatchJobRequest.setJobId(jobContext.getJobId()); + dispatchJobRequest.setTaskId(jobContext.getTaskId()); + dispatchJobRequest.setTaskStatus(JobTaskStatusEnum.FAIL.getStatus()); + dispatchJobRequest.setTaskType(jobContext.getTaskType()); + dispatchJobRequest.setExecuteResult(ExecuteResult.failure(t.getMessage())); + CLIENT.dispatchResult(dispatchJobRequest); + } +} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/NormalJobExecutor.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/NormalJobExecutor.java new file mode 100644 index 00000000..a99c69f4 --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/executor/NormalJobExecutor.java @@ -0,0 +1,10 @@ +package com.aizuda.easy.retry.client.job.core.executor; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-08 17:02 + * @since : 2.4.0 + */ +public abstract class NormalJobExecutor extends AbstractJobExecutor { + +} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/handler/AbstractIJobExecutor.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/handler/AbstractIJobExecutor.java deleted file mode 100644 index 2255b37d..00000000 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/handler/AbstractIJobExecutor.java +++ /dev/null @@ -1,26 +0,0 @@ -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); -} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/handler/SimpleIJobExecutor.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/handler/SimpleIJobExecutor.java deleted file mode 100644 index 44389b6f..00000000 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/handler/SimpleIJobExecutor.java +++ /dev/null @@ -1,17 +0,0 @@ -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; - } -} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/register/scan/JobExecutorScanner.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/register/scan/JobExecutorScanner.java index a8be055c..953afbe6 100644 --- a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/register/scan/JobExecutorScanner.java +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/register/scan/JobExecutorScanner.java @@ -4,6 +4,7 @@ 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.JobContext; import com.aizuda.easy.retry.client.job.core.dto.JobExecutorInfo; import com.aizuda.easy.retry.common.core.log.LogUtils; import lombok.extern.slf4j.Slf4j; @@ -13,6 +14,7 @@ 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.CollectionUtils; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; @@ -52,18 +54,12 @@ public class JobExecutorScanner implements Scanner, ApplicationContextAware { 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)); + if (!JobExecutorInfoCache.isExisted(executorClassName)) { + retryerInfoList.add(new JobExecutorInfo(executorClassName, ReflectionUtils.findMethod(bean.getClass(), "jobExecute"), bean, false)); } } @@ -72,18 +68,22 @@ public class JobExecutorScanner implements Scanner, ApplicationContextAware { JobExecutor jobExecutor = bean.getClass().getAnnotation(JobExecutor.class); if (Objects.nonNull(jobExecutor)) { String executorName = jobExecutor.name(); - if (JobExecutorInfoCache.isExisted(executorName)) { + if (!JobExecutorInfoCache.isExisted(executorName)) { JobExecutorInfo jobExecutorInfo = new JobExecutorInfo( executorName, - ReflectionUtils.findMethod(bean.getClass(), jobExecutor.method()), - bean + ReflectionUtils.findMethod(bean.getClass(), jobExecutor.method(), JobContext.class), + bean, true ); retryerInfoList.add(jobExecutorInfo); } } + if (CollectionUtils.isEmpty(annotatedMethods)) { + continue; + } + // 扫描方法上的注解 for (Map.Entry methodEntry : annotatedMethods.entrySet()) { Method executeMethod = methodEntry.getKey(); @@ -96,7 +96,7 @@ public class JobExecutorScanner implements Scanner, ApplicationContextAware { new JobExecutorInfo( jobExecutor.name(), executeMethod, - bean + bean,true ); retryerInfoList.add(jobExecutorInfo); } diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/timer/StopTaskTimerTask.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/timer/StopTaskTimerTask.java new file mode 100644 index 00000000..313809fe --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/timer/StopTaskTimerTask.java @@ -0,0 +1,24 @@ +package com.aizuda.easy.retry.client.job.core.timer; + +import com.aizuda.easy.retry.client.job.core.cache.ThreadPoolCache; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; + +/** + * @author www.byteblogs.com + * @date 2023-10-08 22:28:53 + * @since 2.4.0 + */ +public class StopTaskTimerTask implements TimerTask { + + private Long taskBatchId; + + public StopTaskTimerTask(Long taskBatchId) { + this.taskBatchId = taskBatchId; + } + + @Override + public void run(Timeout timeout) throws Exception { + ThreadPoolCache.stopThreadPool(taskBatchId); + } +} diff --git a/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/timer/TimerManager.java b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/timer/TimerManager.java new file mode 100644 index 00000000..2fccd92c --- /dev/null +++ b/easy-retry-client/easy-retry-client-job-core/src/main/java/com/aizuda/easy/retry/client/job/core/timer/TimerManager.java @@ -0,0 +1,30 @@ +package com.aizuda.easy.retry.client.job.core.timer; + +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; +import org.springframework.scheduling.concurrent.CustomizableThreadFactory; + +import java.util.concurrent.TimeUnit; + +/** + * @author www.byteblogs.com + * @date 2023-10-08 22:23:57 + * @since 2.4.0 + */ +public class TimerManager { + + private static final HashedWheelTimer wheelTimer; + + static { + wheelTimer = new HashedWheelTimer( + new CustomizableThreadFactory("job-task-timer-wheel-"), 1, + TimeUnit.SECONDS, 1024); + } + private TimerManager() { + } + + public static Timeout add(TimerTask task, long delay, TimeUnit unit) { + return wheelTimer.newTimeout(task, delay, unit); + } +} diff --git a/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/ExecuteResult.java b/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/ExecuteResult.java new file mode 100644 index 00000000..315f4e1f --- /dev/null +++ b/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/ExecuteResult.java @@ -0,0 +1,67 @@ +package com.aizuda.easy.retry.client.model; + +import com.aizuda.easy.retry.common.core.enums.StatusEnum; + +/** + * @author: www.byteblogs.com + * @date : 2023-09-27 09:43 + * @since 2.4.0 + */ +public class ExecuteResult { + private int status; + private Object result; + private String message; + + public ExecuteResult() { + } + + public ExecuteResult(int status, Object result, String message) { + this.status = status; + this.result = result; + this.message = message; + } + + public static ExecuteResult success(Object result) { + return new ExecuteResult(StatusEnum.YES.getStatus(), result, "任务执行成功"); + } + + public static ExecuteResult success() { + return success(null); + } + + public static ExecuteResult failure() { + return failure(null); + } + + public static ExecuteResult failure(Object result) { + return new ExecuteResult(StatusEnum.NO.getStatus(), result, "任务执行失败"); + } + + public static ExecuteResult failure(Object result, String message) { + return new ExecuteResult(StatusEnum.NO.getStatus(), result, message); + } + + public int getStatus() { + return status; + } + + public void setStatus(int status) { + this.status = status; + } + + public Object getResult() { + return result; + } + + public void setResult(Object result) { + this.result = result; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/InterruptJobDTO.java b/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/StopJobDTO.java similarity index 93% rename from easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/InterruptJobDTO.java rename to easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/StopJobDTO.java index 74594e23..ce7d0213 100644 --- a/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/InterruptJobDTO.java +++ b/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/StopJobDTO.java @@ -10,7 +10,7 @@ import javax.validation.constraints.NotNull; * @date : 2023-09-26 15:10 */ @Data -public class InterruptJobDTO { +public class StopJobDTO { @NotNull(message = "jobId 不能为空") private Long jobId; diff --git a/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/DispatchJobDTO.java b/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/request/DispatchJobRequest.java similarity index 65% rename from easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/DispatchJobDTO.java rename to easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/request/DispatchJobRequest.java index 110b2b89..6a38bd85 100644 --- a/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/DispatchJobDTO.java +++ b/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/request/DispatchJobRequest.java @@ -1,4 +1,4 @@ -package com.aizuda.easy.retry.client.model; +package com.aizuda.easy.retry.client.model.request; import lombok.Data; @@ -10,14 +10,20 @@ import javax.validation.constraints.NotNull; * @date : 2023-09-26 15:10 */ @Data -public class DispatchJobDTO { +public class DispatchJobRequest { @NotNull(message = "jobId 不能为空") private Long jobId; + @NotNull(message = "taskBatchId 不能为空") + private Long taskBatchId; + @NotNull(message = "taskId 不能为空") private Long taskId; + @NotNull(message = "taskType 不能为空") + private Integer taskType; + @NotBlank(message = "group 不能为空") private String groupName; @@ -30,5 +36,10 @@ public class DispatchJobDTO { @NotBlank(message = "executorName 不能为空") private String executorName; + private Integer shardingTotal; + + private Integer shardingIndex; + + private Integer executorTimeout; } diff --git a/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/request/DispatchJobResultRequest.java b/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/request/DispatchJobResultRequest.java new file mode 100644 index 00000000..5c16383b --- /dev/null +++ b/easy-retry-common/easy-retry-common-client-api/src/main/java/com/aizuda/easy/retry/client/model/request/DispatchJobResultRequest.java @@ -0,0 +1,30 @@ +package com.aizuda.easy.retry.client.model.request; + +import com.aizuda.easy.retry.client.model.ExecuteResult; +import lombok.Data; + +/** + * @author: www.byteblogs.com + * @date : 2023-09-26 15:10 + */ +@Data +public class DispatchJobResultRequest { + + private Long jobId; + + private Long taskBatchId; + + private Long taskId; + + /** + * 任务类型 + */ + private Integer taskType; + + private String groupName; + + private Integer taskStatus; + + private ExecuteResult executeResult; + +} diff --git a/easy-retry-common/easy-retry-common-core/pom.xml b/easy-retry-common/easy-retry-common-core/pom.xml index f3536cbc..95f73d4b 100644 --- a/easy-retry-common/easy-retry-common-core/pom.xml +++ b/easy-retry-common/easy-retry-common-core/pom.xml @@ -33,11 +33,6 @@ com.aliyun alibaba-dingtalk-service-sdk - - - - - javax.validation validation-api diff --git a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/constant/SystemConstants.java b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/constant/SystemConstants.java index 1331ce66..eb692b32 100644 --- a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/constant/SystemConstants.java +++ b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/constant/SystemConstants.java @@ -66,6 +66,10 @@ public interface SystemConstants { */ String BATCH_REPORT = "/batch/report"; + /** + * 上报job的运行结果 + */ + String REPORT_JOB_DISPATCH_RESULT = "/report/dispatch/result"; } String LOGO = " ___ ___ _ \n" + diff --git a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobOperationReasonEnum.java b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobOperationReasonEnum.java new file mode 100644 index 00000000..a889a2d6 --- /dev/null +++ b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobOperationReasonEnum.java @@ -0,0 +1,26 @@ +package com.aizuda.easy.retry.common.core.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 标识某个操作的具体原因 + * + * @author www.byteblogs.com + * @date 2023-10-07 23:05:50 + * @since 2.4.0 + */ +@AllArgsConstructor +@Getter +public enum JobOperationReasonEnum { + + NONE(0, StrUtil.EMPTY), + EXECUTE_TIMEOUT(1, "执行超时"), + NOT_CLIENT(2, "无客户端节点"), + ; + + private final int reason; + private final String desc; + +} diff --git a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobTaskBatchStatusEnum.java b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobTaskBatchStatusEnum.java new file mode 100644 index 00000000..35d79286 --- /dev/null +++ b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobTaskBatchStatusEnum.java @@ -0,0 +1,55 @@ +package com.aizuda.easy.retry.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.List; + +/** + * @author: www.byteblogs.com + * @date : 2023-09-26 14:26 + * @since : 2.4.0 + */ +@AllArgsConstructor +@Getter +public enum JobTaskBatchStatusEnum { + + /** + * 待处理 + */ + WAITING(1), + + /** + * 运行中 + */ + RUNNING(2), + + /** + * 处理成功 + */ + SUCCESS(3), + + /** + * 处理失败 + */ + FAIL(4), + + /** + * 任务停止 + */ + STOP(5), + + /** + * 取消 + */ + CANCEL(6), + ; + + private final int status; + + public static final List NOT_COMPLETE = Arrays.asList(WAITING.status, RUNNING.status); + + public static final List COMPLETED = Arrays.asList(SUCCESS.status, FAIL.status, STOP.status, CANCEL.status); + +} diff --git a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobTaskStatusEnum.java b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobTaskStatusEnum.java new file mode 100644 index 00000000..e81b0f2b --- /dev/null +++ b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/enums/JobTaskStatusEnum.java @@ -0,0 +1,50 @@ +package com.aizuda.easy.retry.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.List; + +/** + * @author: www.byteblogs.com + * @date : 2023-09-26 14:26 + */ +@AllArgsConstructor +@Getter +public enum JobTaskStatusEnum { + + /** + * 待处理 + */ + WAITING(1), + + /** + * 处理中 + */ + RUNNING(2), + + /** + * 处理成功 + */ + SUCCESS(3), + + /** + * 处理失败 + */ + FAIL(4), + + /** + * 任务停止成功 + */ + STOP(5), + + + ; + + private final int status; + + public static final List NOT_COMPLETE = Arrays.asList(WAITING.status, RUNNING.status); + + public static final List COMPLETED = Arrays.asList(SUCCESS.status, FAIL.status, STOP.status); +} diff --git a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/handler/RestExceptionHandler.java b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/handler/RestExceptionHandler.java index ca04e52f..6bf37433 100644 --- a/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/handler/RestExceptionHandler.java +++ b/easy-retry-common/easy-retry-common-core/src/main/java/com/aizuda/easy/retry/common/core/handler/RestExceptionHandler.java @@ -30,7 +30,12 @@ import java.util.stream.Collectors; * @author: byteblogs * @date: 2019/09/30 17:02 */ -@ControllerAdvice(basePackages = {"com.aizuda.easy.retry.client.core", "com.aizuda.easy.retry.server"} ) +@ControllerAdvice(basePackages = { + "com.aizuda.easy.retry.client.core", + "com.aizuda.easy.retry.client.job.core", + "com.aizuda.easy.retry.client.common", + "com.aizuda.easy.retry.server", +} ) @Slf4j @ResponseBody public class RestExceptionHandler { diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskInstanceMapper.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskBatchMapper.java similarity index 54% rename from easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskInstanceMapper.java rename to easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskBatchMapper.java index dbdca5ac..a76c6cd3 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskInstanceMapper.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskBatchMapper.java @@ -1,18 +1,20 @@ package com.aizuda.easy.retry.template.datasource.persistence.mapper; -import com.aizuda.easy.retry.template.datasource.persistence.po.JobTaskInstance; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTaskBatch; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; /** *

- * 任务实例 Mapper 接口 + * 调度任务 Mapper 接口 *

* * @author www.byteblogs.com * @since 2023-09-24 */ @Mapper -public interface JobTaskInstanceMapper extends BaseMapper { +public interface JobTaskBatchMapper extends BaseMapper { + int updateJobTaskBatchStatus(@Param("taskBatchId") Long taskBatchId, @Param("taskStatus") Integer taskStatus); } diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskMapper.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskMapper.java index d146f5bf..ddd6eb21 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskMapper.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/mapper/JobTaskMapper.java @@ -6,7 +6,7 @@ import org.apache.ibatis.annotations.Mapper; /** *

- * 调度任务 Mapper 接口 + * 任务实例 Mapper 接口 *

* * @author www.byteblogs.com diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/GroupConfig.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/GroupConfig.java index 5e35abec..5ed1d502 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/GroupConfig.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/GroupConfig.java @@ -27,6 +27,8 @@ public class GroupConfig implements Serializable { private Integer initScene; + private Integer bucketIndex; + private String description; private LocalDateTime createDt; diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Job.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Job.java index 852eb7f1..2d13f5ab 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Job.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/Job.java @@ -109,6 +109,16 @@ public class Job implements Serializable { */ private Integer retryInterval; + /** + * 任务类型 + */ + private Integer taskType; + + /** + * 并行数 + */ + private Integer parallelNum; + /** * bucket */ diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobLogMessage.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobLogMessage.java index 0829dda4..972500d2 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobLogMessage.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobLogMessage.java @@ -3,8 +3,10 @@ package com.aizuda.easy.retry.template.datasource.persistence.po; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; + import java.io.Serializable; import java.time.LocalDateTime; + import lombok.Getter; import lombok.Setter; @@ -26,7 +28,7 @@ public class JobLogMessage implements Serializable { /** * 主键 */ - @TableId(value = "id", type = IdType.AUTO) + @TableId(value = "id", type = IdType.AUTO) private Long id; /** @@ -42,18 +44,23 @@ public class JobLogMessage implements Serializable { /** * 任务实例id */ - private Long taskId; + private Long taskBatchId; /** * 调度任务id */ - private Long taskInstanceId; + private Long taskId; /** * 创建时间 */ private LocalDateTime createDt; + /** + * 客户端信息 + */ + private String clientAddress; + /** * 调度信息 */ diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTask.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTask.java index b469ec21..ada7dc80 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTask.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTask.java @@ -12,7 +12,7 @@ import lombok.Setter; /** *

- * 调度任务 + * 任务实例 *

* * @author www.byteblogs.com @@ -37,24 +37,54 @@ public class JobTask implements Serializable { private String groupName; /** - * 任务id + * 任务信息id */ private Long jobId; + /** + * 调度任务id + */ + private Long taskBatchId; + + /** + * 父执行器id + */ + private Long parentId; + + /** + * 执行的状态 0、失败 1、成功 + */ + private Integer executeStatus; + /** * 重试次数 */ private Integer retryCount; /** - * 任务状态 0、失败 1、成功 + * 执行结果 */ - private Integer taskStatus; + private String resultMessage; /** - * 客户端节点id + * 客户端ID */ - private String hostId; + private String clientId; + + /** + * 执行方法参数 + */ + private String argsStr; + + /** + * 参数类型 text/json + */ + private String argsType; + + /** + * 扩展字段 + */ + private String extAttrs; /** * 创建时间 @@ -66,10 +96,5 @@ public class JobTask implements Serializable { */ private LocalDateTime updateDt; - /** - * 逻辑删除 1、删除 - */ - private Integer deleted; - } diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTaskInstance.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTaskBatch.java similarity index 68% rename from easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTaskInstance.java rename to easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTaskBatch.java index 3af883ad..80d546c5 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTaskInstance.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/JobTaskBatch.java @@ -3,14 +3,16 @@ package com.aizuda.easy.retry.template.datasource.persistence.po; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; + import java.io.Serializable; import java.time.LocalDateTime; + import lombok.Getter; import lombok.Setter; /** *

- * 任务实例 + * 调度任务 *

* * @author www.byteblogs.com @@ -18,15 +20,15 @@ import lombok.Setter; */ @Getter @Setter -@TableName("job_task_instance") -public class JobTaskInstance implements Serializable { +@TableName("job_task_batch") +public class JobTaskBatch implements Serializable { private static final long serialVersionUID = 1L; /** * 主键 */ - @TableId(value = "id", type = IdType.AUTO) + @TableId(value = "id", type = IdType.AUTO) private Long id; /** @@ -40,34 +42,34 @@ public class JobTaskInstance implements Serializable { private Long jobId; /** - * 调度任务id + * 任务状态 0、失败 1、成功 */ - private Long taskId; - - /** - * 父执行器id - */ - private Long parentId; - - /** - * 执行的状态 0、失败 1、成功 - */ - private Integer executeStatus; - - /** - * 执行结果 - */ - private String resultMessage; + private Integer taskStatus; /** * 创建时间 */ private LocalDateTime createDt; + /** + * 任务执行时间 + */ + private LocalDateTime executionAt; + + /** + * 操作原因 + */ + private Integer operationReason; + /** * 修改时间 */ private LocalDateTime updateDt; + /** + * 逻辑删除 1、删除 + */ + private Integer deleted; + } diff --git a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/SceneConfig.java b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/SceneConfig.java index b2bd9324..ddd94c3c 100644 --- a/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/SceneConfig.java +++ b/easy-retry-datasource/easy-retry-datasource-template/src/main/java/com/aizuda/easy/retry/template/datasource/persistence/po/SceneConfig.java @@ -29,8 +29,6 @@ public class SceneConfig implements Serializable { private Long deadlineRequest; - private Integer bucketIndex; - private LocalDateTime createDt; private LocalDateTime updateDt; diff --git a/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskBatchMapper.xml b/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskBatchMapper.xml new file mode 100644 index 00000000..af4ed398 --- /dev/null +++ b/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskBatchMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + update job_task_batch + set task_status = #{taskStatus} + + id = #{taskBatchId} + + and EXISTS (select id from job_task where task_batch_id = #{taskBatchId} and execute_status = 4) + + + and NOT EXISTS (select id from job_task where task_batch_id = #{taskBatchId} and execute_status IN(1, 2, 4, 5)) + + + and NOT EXISTS (select id from job_task where task_batch_id = #{taskBatchId} and execute_status IN(1, 2)) + + + + + + diff --git a/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskInstanceMapper.xml b/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskInstanceMapper.xml deleted file mode 100644 index 711a0800..00000000 --- a/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskInstanceMapper.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskMapper.xml b/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskMapper.xml index 487f89cb..fc8de3df 100644 --- a/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskMapper.xml +++ b/easy-retry-datasource/easy-retry-mysql-datasource/src/main/resources/mysql/mapper/JobTaskMapper.xml @@ -7,11 +7,12 @@ - - + + + + - diff --git a/easy-retry-server/easy-retry-server-common/pom.xml b/easy-retry-server/easy-retry-server-common/pom.xml index 2befcf2a..b0caf077 100644 --- a/easy-retry-server/easy-retry-server-common/pom.xml +++ b/easy-retry-server/easy-retry-server-common/pom.xml @@ -86,6 +86,10 @@ com.squareup.okhttp3 okhttp
+ + com.github.rholder + guava-retrying + diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/akka/ActorGenerator.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/akka/ActorGenerator.java index 3fc845e7..48dc4f99 100644 --- a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/akka/ActorGenerator.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/akka/ActorGenerator.java @@ -28,6 +28,10 @@ public class ActorGenerator { public static final String SCAN_JOB_ACTOR = "ScanJobActor"; public static final String JOB_TASK_PREPARE_ACTOR = "JobTaskPrepareActor"; public static final String JOB_EXECUTOR_ACTOR = "JobExecutorActor"; + public static final String JOB_EXECUTOR_RESULT_ACTOR = "JobExecutorResultActor"; + public static final String JOB_LOG_ACTOR = "JobLogActor"; + public static final String REAL_JOB_EXECUTOR_ACTOR = "RealJobExecutorActor"; + public static final String REAL_STOP_TASK_INSTANCE_ACTOR = "RealStopTaskInstanceActor"; private ActorGenerator() {} @@ -149,6 +153,42 @@ public class ActorGenerator { return getJobActorSystem().actorOf(getSpringExtension().props(JOB_EXECUTOR_ACTOR)); } + /** + * Job任务执行结果actor + * + * @return actor 引用 + */ + public static ActorRef jobTaskExecutorResultActor() { + return getJobActorSystem().actorOf(getSpringExtension().props(JOB_EXECUTOR_RESULT_ACTOR)); + } + + /** + * Job任务向客户端发起请求阶段actor + * + * @return actor 引用 + */ + public static ActorRef jobRealTaskExecutorActor() { + return getJobActorSystem().actorOf(getSpringExtension().props(REAL_JOB_EXECUTOR_ACTOR)); + } + + /** + * Job任务向客户端发起请求阶段actor + * + * @return actor 引用 + */ + public static ActorRef jobRealStopTaskInstanceActor() { + return getJobActorSystem().actorOf(getSpringExtension().props(REAL_STOP_TASK_INSTANCE_ACTOR)); + } + + /** + * Job日志actor + * + * @return actor 引用 + */ + public static ActorRef jobLogActor() { + return getJobActorSystem().actorOf(getSpringExtension().props(JOB_LOG_ACTOR)); + } + public static SpringExtension getSpringExtension() { return SpringContext.getBeanByType(SpringExtension.class); } diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/RpcClient.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/RpcClient.java index 5ba3b88a..635da1b1 100644 --- a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/RpcClient.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/RpcClient.java @@ -1,9 +1,9 @@ package com.aizuda.easy.retry.server.common.client; -import com.aizuda.easy.retry.client.model.DispatchJobDTO; +import com.aizuda.easy.retry.client.model.request.DispatchJobRequest; import com.aizuda.easy.retry.client.model.DispatchRetryDTO; import com.aizuda.easy.retry.client.model.DispatchRetryResultDTO; -import com.aizuda.easy.retry.client.model.InterruptJobDTO; +import com.aizuda.easy.retry.client.model.StopJobDTO; import com.aizuda.easy.retry.client.model.RetryCallbackDTO; import com.aizuda.easy.retry.common.core.model.EasyRetryHeaders; import com.aizuda.easy.retry.common.core.model.Result; @@ -26,10 +26,10 @@ public interface RpcClient { @Mapping(path = "/retry/callback/v1", method = RequestMethod.POST) Result callback(@Body RetryCallbackDTO retryCallbackDTO); - @Mapping(path = "/job/interrupt/v1", method = RequestMethod.POST) - Result interrupt(@Body InterruptJobDTO interruptJobDTO); + @Mapping(path = "/job/stop/v1", method = RequestMethod.POST) + Result stop(@Body StopJobDTO stopJobDTO); @Mapping(path = "/job/dispatch/v1", method = RequestMethod.POST) - Result dispatch(@Body DispatchJobDTO dispatchJobDTO); + Result dispatch(@Body DispatchJobRequest dispatchJobRequest); } diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/RpcClientInvokeHandler.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/RpcClientInvokeHandler.java index e02d0809..346d1a16 100644 --- a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/RpcClientInvokeHandler.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/RpcClientInvokeHandler.java @@ -4,6 +4,7 @@ import cn.hutool.core.lang.Assert; import cn.hutool.core.util.URLUtil; import com.aizuda.easy.retry.common.core.constant.SystemConstants; import com.aizuda.easy.retry.common.core.context.SpringContext; +import com.aizuda.easy.retry.common.core.log.LogUtils; import com.aizuda.easy.retry.common.core.model.Result; import com.aizuda.easy.retry.common.core.util.HostUtils; import com.aizuda.easy.retry.common.core.util.JsonUtil; @@ -15,13 +16,23 @@ import com.aizuda.easy.retry.server.common.client.annotation.Param; import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; import com.aizuda.easy.retry.server.common.handler.ClientNodeAllocateHandler; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.github.rholder.retry.Attempt; +import com.github.rholder.retry.RetryException; +import com.github.rholder.retry.RetryListener; +import com.github.rholder.retry.Retryer; +import com.github.rholder.retry.RetryerBuilder; +import com.github.rholder.retry.StopStrategies; +import com.github.rholder.retry.WaitStrategies; import lombok.Data; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; @@ -34,6 +45,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; /** * 请求处理器 @@ -71,11 +84,23 @@ public class RpcClientInvokeHandler implements InvocationHandler { Mapping annotation = method.getAnnotation(Mapping.class); Assert.notNull(annotation, () -> new EasyRetryServerException("@Mapping cannot be null")); + if (annotation.failover()) { + return doFailoverHandler(method, args, annotation); + } + + return requestRemote(method, args, annotation, 0); + } + + @NotNull + private Result doFailoverHandler(final Method method, final Object[] args, final Mapping annotation) + throws Throwable { Set serverNodeSet = CacheRegisterTable.getServerNodeSet(groupName); + // 最多调用size次 int size = serverNodeSet.size(); for (int count = 1; count <= size; count++) { - log.info("Start request client. count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, hostId, hostIp, hostPort, HostUtils.getIp()); + log.info("Start request client. count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, hostId, + hostIp, hostPort, HostUtils.getIp()); Result result = requestRemote(method, args, annotation, count); if (Objects.nonNull(result)) { return result; @@ -85,7 +110,7 @@ public class RpcClientInvokeHandler implements InvocationHandler { throw new EasyRetryServerException("No available nodes."); } - private Result requestRemote(Method method, Object[] args, Mapping mapping, int count) { + private Result requestRemote(Method method, Object[] args, Mapping mapping, int count) throws Throwable { try { @@ -99,23 +124,31 @@ public class RpcClientInvokeHandler implements InvocationHandler { RestTemplate restTemplate = SpringContext.CONTEXT.getBean(RestTemplate.class); - ResponseEntity response = restTemplate.exchange( - // 拼接 url?a=1&b=1 - getUrl(mapping, parasResult.paramMap).toString(), - // post or get - HttpMethod.valueOf(mapping.method().name()), - // body - new HttpEntity<>(parasResult.body, parasResult.requestHeaders), - // 返回值类型 - Result.class); + Retryer retryer = buildResultRetryer(mapping); - log.info("Request client success. count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, hostId, hostIp, hostPort, HostUtils.getIp()); + Result result = retryer.call(() -> { + ResponseEntity response = restTemplate.exchange( + // 拼接 url?a=1&b=1 + getUrl(mapping, parasResult.paramMap).toString(), + // post or get + HttpMethod.valueOf(mapping.method().name()), + // body + new HttpEntity<>(parasResult.body, parasResult.requestHeaders), + // 返回值类型 + Result.class); - return Objects.requireNonNull(response.getBody()); + return Objects.requireNonNull(response.getBody()); + }); + + log.info("Request client success. count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, hostId, + hostIp, hostPort, HostUtils.getIp()); + + return result; } catch (RestClientException ex) { // 网络异常 - if (ex instanceof ResourceAccessException) { - log.error("request client I/O error, count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, hostId, hostIp, hostPort, HostUtils.getIp(), ex); + if (ex instanceof ResourceAccessException && mapping.failover()) { + log.error("request client I/O error, count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, + hostId, hostIp, hostPort, HostUtils.getIp(), ex); // 进行路由剔除处理 CacheRegisterTable.remove(groupName, hostId); @@ -135,15 +168,43 @@ public class RpcClientInvokeHandler implements InvocationHandler { } else { // 其他异常继续抛出 - log.error("request client error.count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, hostId, hostIp, hostPort, HostUtils.getIp(), ex); + log.error("request client error.count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, + hostId, hostIp, hostPort, HostUtils.getIp(), ex); throw ex; } } catch (Exception ex) { - log.error("request client unknown exception. count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", count, hostId, hostIp, hostPort, HostUtils.getIp(), ex); - throw ex; + log.error("request client unknown exception. count:[{}] clientId:[{}] clientAddr:[{}:{}] serverIp:[{}]", + count, hostId, hostIp, hostPort, HostUtils.getIp(), ex); + + Throwable throwable = ex; + if (ex.getClass().isAssignableFrom(RetryException.class)) { + RetryException re = (RetryException) ex; + throwable = re.getLastFailedAttempt().getExceptionCause(); + } + + throw throwable; } - return null; + return null; + } + + private Retryer buildResultRetryer(Mapping mapping) throws InstantiationException, IllegalAccessException, NoSuchMethodException { + Class retryListenerClazz = mapping.retryListener(); + RetryListener retryListener = retryListenerClazz.newInstance(); + Method method = retryListenerClazz.getMethod("onRetry", Attempt.class); + + Retryer retryer = RetryerBuilder.newBuilder() + .retryIfException(throwable -> mapping.failRetry()) + .withStopStrategy(StopStrategies.stopAfterAttempt(mapping.retryTimes())) + .withWaitStrategy(WaitStrategies.fixedWait(mapping.retryInterval(), TimeUnit.SECONDS)) + .withRetryListener(new RetryListener() { + @Override + public void onRetry(Attempt attempt) { + ReflectionUtils.invokeMethod(method, retryListener, attempt); + } + }) + .build(); + return retryer; } private StringBuilder getUrl(Mapping mapping, Map paramMap) { diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/SimpleRetryListener.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/SimpleRetryListener.java new file mode 100644 index 00000000..3ab428b1 --- /dev/null +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/SimpleRetryListener.java @@ -0,0 +1,17 @@ +package com.aizuda.easy.retry.server.common.client; + +import com.github.rholder.retry.Attempt; +import com.github.rholder.retry.RetryListener; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-09 09:24 + * @since : 2.4.0 + */ +public class SimpleRetryListener implements RetryListener { + + @Override + public void onRetry(final Attempt attempt) { + + } +} diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/annotation/Mapping.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/annotation/Mapping.java index 432aeb59..8fd292ec 100644 --- a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/annotation/Mapping.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/client/annotation/Mapping.java @@ -1,6 +1,8 @@ package com.aizuda.easy.retry.server.common.client.annotation; import com.aizuda.easy.retry.server.common.client.RequestMethod; +import com.aizuda.easy.retry.server.common.client.SimpleRetryListener; +import com.github.rholder.retry.RetryListener; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -24,4 +26,16 @@ public @interface Mapping { String path() default ""; + boolean failover() default false; + + boolean failRetry() default false; + + int retryTimes() default 3; + + int retryInterval() default 1; + + Class retryListener() default SimpleRetryListener.class; + + + } diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/PartitionTask.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/PartitionTask.java new file mode 100644 index 00000000..982b68b2 --- /dev/null +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/PartitionTask.java @@ -0,0 +1,14 @@ +package com.aizuda.easy.retry.server.common.dto; + +import lombok.Data; + +/** + * @author: www.byteblogs.com + * @date : 2022-10-28 18:45 + */ +@Data +public class PartitionTask { + + protected Long id; + +} diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/RegisterNodeInfo.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/RegisterNodeInfo.java index 5203c71e..8f7733c2 100644 --- a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/RegisterNodeInfo.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/RegisterNodeInfo.java @@ -2,6 +2,7 @@ package com.aizuda.easy.retry.server.common.dto; import lombok.Data; +import java.text.MessageFormat; import java.time.LocalDateTime; /** @@ -13,6 +14,8 @@ import java.time.LocalDateTime; @Data public class RegisterNodeInfo implements Comparable { + private static final String URL = "http://{0}:{1}/{2}"; + private String groupName; private String hostId; @@ -27,6 +30,10 @@ public class RegisterNodeInfo implements Comparable { private String contextPath; + public String fullUrl() { + return MessageFormat.format(URL, hostIp, hostPort.toString(), contextPath); + } + @Override public int compareTo(RegisterNodeInfo info) { return hostId.compareTo(info.hostId); diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/ScanTask.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/ScanTask.java index ee3bc786..cf5fadda 100644 --- a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/ScanTask.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/dto/ScanTask.java @@ -2,6 +2,7 @@ package com.aizuda.easy.retry.server.common.dto; import lombok.Data; +import java.util.List; import java.util.Set; /** diff --git a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/handler/ServerNodeBalance.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/handler/ServerNodeBalance.java index e1a724c5..f68751ab 100644 --- a/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/handler/ServerNodeBalance.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/handler/ServerNodeBalance.java @@ -222,7 +222,6 @@ public class ServerNodeBalance implements Lifecycle, Runnable { try { TimeUnit.SECONDS.sleep(systemProperties.getLoadBalanceCycleTime()); } catch (InterruptedException e) { - LogUtils.error(log, "check balance interrupt"); Thread.currentThread().interrupt(); } } diff --git a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/listener/EndListener.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/listener/EndListener.java similarity index 92% rename from easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/listener/EndListener.java rename to easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/listener/EndListener.java index 74a4660e..cf43f0f2 100644 --- a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/listener/EndListener.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/listener/EndListener.java @@ -1,4 +1,4 @@ -package com.aizuda.easy.retry.server.retry.task.support.listener; +package com.aizuda.easy.retry.server.common.listener; import com.aizuda.easy.retry.common.core.log.LogUtils; import com.aizuda.easy.retry.server.common.Lifecycle; diff --git a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/listener/StartListener.java b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/listener/StartListener.java similarity index 95% rename from easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/listener/StartListener.java rename to easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/listener/StartListener.java index 8d9922db..7d94d680 100644 --- a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/listener/StartListener.java +++ b/easy-retry-server/easy-retry-server-common/src/main/java/com/aizuda/easy/retry/server/common/listener/StartListener.java @@ -1,4 +1,4 @@ -package com.aizuda.easy.retry.server.retry.task.support.listener; +package com.aizuda.easy.retry.server.common.listener; import com.aizuda.easy.retry.common.core.constant.SystemConstants; import com.aizuda.easy.retry.common.core.log.LogUtils; diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/EasyRetryJobTaskStarter.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/EasyRetryJobTaskStarter.java new file mode 100644 index 00000000..0fcf1cc7 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/EasyRetryJobTaskStarter.java @@ -0,0 +1,28 @@ +package com.aizuda.easy.retry.server.job; + +import com.aizuda.easy.retry.server.common.Lifecycle; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author www.byteblogs.com + * @date 2023-09-29 23:29:44 + * @since 2.4.0 + */ +@Component +@Slf4j +public class EasyRetryJobTaskStarter implements Lifecycle { + + @Override + public void start() { + // 检查是否还有未执行的任务,如果有则直接失败 + log.info("easy-retry-job-task starting..."); + + log.info("easy-retry-job-task completed"); + } + + @Override + public void close() { + // 关闭还未执行的任务 + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/BlockStrategy.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/BlockStrategy.java index cce133c4..9ffe5770 100644 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/BlockStrategy.java +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/BlockStrategy.java @@ -7,6 +7,5 @@ import com.aizuda.easy.retry.server.job.task.strategy.BlockStrategies.BlockStrat * @date : 2023-09-25 17:53 */ public interface BlockStrategy { - - boolean block(BlockStrategyContext context); + void block(BlockStrategyContext context); } diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/JobTaskConverter.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/JobTaskConverter.java new file mode 100644 index 00000000..30b48b55 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/JobTaskConverter.java @@ -0,0 +1,79 @@ +package com.aizuda.easy.retry.server.job.task; + +import com.aizuda.easy.retry.client.model.request.DispatchJobRequest; +import com.aizuda.easy.retry.client.model.request.DispatchJobResultRequest; +import com.aizuda.easy.retry.server.job.task.dto.*; +import com.aizuda.easy.retry.server.job.task.generator.batch.JobTaskBatchGeneratorContext; +import com.aizuda.easy.retry.server.job.task.generator.task.JobTaskGenerateContext; +import com.aizuda.easy.retry.server.job.task.handler.callback.ClientCallbackContext; +import com.aizuda.easy.retry.server.job.task.handler.executor.JobExecutorContext; +import com.aizuda.easy.retry.server.job.task.handler.stop.TaskStopJobContext; +import com.aizuda.easy.retry.server.job.task.strategy.BlockStrategies; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobLogMessage; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * @author: www.byteblogs.com + * @date : 2021-11-26 15:22 + */ +@Mapper +public interface JobTaskConverter { + + JobTaskConverter INSTANCE = Mappers.getMapper(JobTaskConverter.class); + + @Mappings( + @Mapping(source = "id", target = "jobId") + ) + JobTaskPrepareDTO toJobTaskPrepare(JobPartitionTask job); + + JobTaskBatchGeneratorContext toJobTaskGeneratorContext(JobTaskPrepareDTO jobTaskPrepareDTO); + + JobTaskBatchGeneratorContext toJobTaskGeneratorContext(BlockStrategies.BlockStrategyContext context); + + JobTaskGenerateContext toJobTaskInstanceGenerateContext(JobExecutorContext context); + + JobTask toJobTaskInstance(JobTaskGenerateContext context); + + BlockStrategies.BlockStrategyContext toBlockStrategyContext(JobTaskPrepareDTO prepareDTO); + + TaskStopJobContext toStopJobContext(BlockStrategies.BlockStrategyContext context); + + JobLogMessage toJobLogMessage(JobLogDTO jobLogDTO); + + JobLogDTO toJobLogDTO(JobExecutorContext context); + + JobLogDTO toJobLogDTO(JobExecutorResultDTO resultDTO); + + JobLogDTO toJobLogDTO(BaseDTO baseDTO); + + JobLogDTO toJobLogDTO(DispatchJobResultRequest request); + + ClientCallbackContext toClientCallbackContext(DispatchJobResultRequest request); + + DispatchJobRequest toDispatchJobRequest(RealJobExecutorDTO realJobExecutorDTO); + + @Mappings({ + @Mapping(source = "job.groupName", target = "groupName"), + @Mapping(source = "jobTask.id", target = "taskId"), + @Mapping(source = "jobTask.argsStr", target = "argsStr"), + @Mapping(source = "jobTask.argsType", target = "argsType"), + @Mapping(source = "jobTask.extAttrs", target = "extAttrs") + }) + RealJobExecutorDTO toRealJobExecutorDTO(Job job, JobTask jobTask); + + JobExecutorResultDTO toJobExecutorResultDTO(ClientCallbackContext context); + + JobExecutorResultDTO toJobExecutorResultDTO(JobTask jobTask); + + RealStopTaskInstanceDTO toRealStopTaskInstanceDTO(TaskStopJobContext context); + + List toJobPartitionTasks(List jobs); + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobExecutorActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobExecutorActor.java new file mode 100644 index 00000000..8ec3f137 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobExecutorActor.java @@ -0,0 +1,55 @@ +package com.aizuda.easy.retry.server.job.task.dispatch; + +import akka.actor.AbstractActor; +import com.aizuda.easy.retry.common.core.log.LogUtils; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.dto.TaskExecuteDTO; +import com.aizuda.easy.retry.server.job.task.handler.executor.JobExecutor; +import com.aizuda.easy.retry.server.job.task.handler.executor.JobExecutorContext; +import com.aizuda.easy.retry.server.job.task.handler.executor.JobExecutorFactory; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * @author: www.byteblogs.com + * @date : 2023-09-25 17:41 + * @since : 2.4.0 + */ +@Component(ActorGenerator.JOB_EXECUTOR_ACTOR) +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@Slf4j +public class JobExecutorActor extends AbstractActor { + @Autowired + private JobMapper jobMapper; + + @Override + public Receive createReceive() { + return receiveBuilder().match(TaskExecuteDTO.class, taskExecute -> { + try { + doExecute(taskExecute); + } catch (Exception e) { + LogUtils.error(log, "job executor exception. [{}]", taskExecute, e); + } finally { + getContext().stop(getSelf()); + } + }).build(); + } + + private void doExecute(final TaskExecuteDTO taskExecute) { + Job job = jobMapper.selectById(taskExecute.getJobId()); + JobExecutor jobExecutor = JobExecutorFactory.getJobExecutor(job.getTaskType()); + + JobExecutorContext context = new JobExecutorContext(); + context.setTaskBatchId(taskExecute.getTaskBatchId()); + context.setGroupName(taskExecute.getGroupName()); + context.setJobId(job.getId()); + context.setTaskType(job.getTaskType()); + jobExecutor.execute(context); + + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobExecutorResultActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobExecutorResultActor.java new file mode 100644 index 00000000..6c4f0749 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobExecutorResultActor.java @@ -0,0 +1,76 @@ +package com.aizuda.easy.retry.server.job.task.dispatch; + +import akka.actor.AbstractActor; +import akka.actor.ActorRef; +import cn.hutool.core.lang.Assert; +import com.aizuda.easy.retry.common.core.util.JsonUtil; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobExecutorResultDTO; +import com.aizuda.easy.retry.server.job.task.dto.JobLogDTO; +import com.aizuda.easy.retry.server.job.task.handler.helper.JobTaskBatchHelper; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskBatchMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import java.util.Objects; + +/** + * @author www.byteblogs.com + * @date 2023-10-05 17:16:35 + * @since 2.4.0 + */ +@Component(ActorGenerator.JOB_EXECUTOR_RESULT_ACTOR) +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@Slf4j +public class JobExecutorResultActor extends AbstractActor { + + @Autowired + private JobTaskMapper jobTaskMapper; + @Autowired + private TransactionTemplate transactionTemplate; + @Autowired + private JobTaskBatchHelper jobTaskBatchHelper; + + @Override + public Receive createReceive() { + return receiveBuilder().match(JobExecutorResultDTO.class, result -> { + + transactionTemplate.execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(final TransactionStatus status) { + JobTask jobTask = new JobTask(); + jobTask.setExecuteStatus(result.getTaskStatus()); + if (Objects.nonNull(result.getResult())) { + jobTask.setResultMessage(JsonUtil.toJsonString(result.getResult())); + } + + Assert.isTrue(1 == jobTaskMapper.update(jobTask, + new LambdaUpdateWrapper().eq(JobTask::getId, result.getTaskId())), + ()-> new EasyRetryServerException("更新任务实例失败")); + + // 更新批次上的状态 + jobTaskBatchHelper.complete(result.getTaskBatchId()); + } + }); + + JobLogDTO jobLogDTO = JobTaskConverter.INSTANCE.toJobLogDTO(result); + jobLogDTO.setMessage(result.getMessage()); + jobLogDTO.setClientId(result.getClientId()); + jobLogDTO.setTaskId(result.getTaskId()); + ActorRef actorRef = ActorGenerator.jobLogActor(); + actorRef.tell(jobLogDTO, actorRef); + + }).build(); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobLogActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobLogActor.java new file mode 100644 index 00000000..bc4bc5ba --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobLogActor.java @@ -0,0 +1,61 @@ +package com.aizuda.easy.retry.server.job.task.dispatch; + +import akka.actor.AbstractActor; +import cn.hutool.core.util.StrUtil; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.common.cache.CacheRegisterTable; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobLogDTO; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobLogMessageMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobLogMessage; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.Objects; +import java.util.Optional; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 22:32:30 + * @since 2.4.0 + */ +@Component(ActorGenerator.JOB_LOG_ACTOR) +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@Slf4j +public class JobLogActor extends AbstractActor { + + @Autowired + private JobLogMessageMapper jobLogMessageMapper; + + @Override + public Receive createReceive() { + return receiveBuilder().match(JobLogDTO.class, (jobLogDTO -> { + try { + saveLogMessage(jobLogDTO); + } catch (Exception e) { + log.error("保存日志异常.", e); + } finally { + getContext().stop(getSelf()); + } + })).build(); + + } + + private void saveLogMessage(JobLogDTO jobLogDTO) { + JobLogMessage jobLogMessage = JobTaskConverter.INSTANCE.toJobLogMessage(jobLogDTO); + if (Objects.nonNull(jobLogDTO.getClientId())) { + Optional.ofNullable(CacheRegisterTable.getServerNode(jobLogDTO.getGroupName(), jobLogDTO.getClientId())).ifPresent(registerNodeInfo -> { + jobLogMessage.setClientAddress(registerNodeInfo.fullUrl()); + }); + } + + jobLogMessage.setCreateDt(LocalDateTime.now()); + jobLogMessage.setMessage(Optional.ofNullable(jobLogDTO.getMessage()).orElse(StrUtil.EMPTY)); + jobLogMessage.setTaskId(Optional.ofNullable(jobLogMessage.getTaskId()).orElse(0L)); + jobLogMessageMapper.insert(jobLogMessage); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobTaskPrepareActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobTaskPrepareActor.java new file mode 100644 index 00000000..61341b96 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/JobTaskPrepareActor.java @@ -0,0 +1,75 @@ +package com.aizuda.easy.retry.server.job.task.dispatch; + +import akka.actor.AbstractActor; +import com.aizuda.easy.retry.common.core.context.SpringContext; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; +import com.aizuda.easy.retry.server.job.task.handler.prepare.JobPrePareHandler; +import com.aizuda.easy.retry.server.job.task.handler.prepare.TerminalJobPrepareHandler; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskBatchMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTaskBatch; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import static com.aizuda.easy.retry.common.core.enums.JobTaskBatchStatusEnum.NOT_COMPLETE; + +/** + * 调度任务准备阶段 + * + * @author www.byteblogs.com + * @date 2023-09-25 22:20:53 + * @since + */ +@Component(ActorGenerator.JOB_TASK_PREPARE_ACTOR) +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@Slf4j +public class JobTaskPrepareActor extends AbstractActor { + + @Autowired + private JobTaskBatchMapper jobTaskBatchMapper; + @Autowired + private List prePareHandlers; + + @Override + public Receive createReceive() { + return receiveBuilder().match(JobTaskPrepareDTO.class, job -> { + try { + doPrepare(job); + } catch (Exception e) { + log.error("预处理节点异常", e); + } finally { + getContext().stop(getSelf()); + } + }).build(); + } + + private void doPrepare(JobTaskPrepareDTO prepare) { + + List notCompleteJobTaskBatchList = jobTaskBatchMapper.selectList(new LambdaQueryWrapper() + .eq(JobTaskBatch::getJobId, prepare.getJobId()) + .in(JobTaskBatch::getTaskStatus, NOT_COMPLETE)); + + // 说明所以任务已经完成 + if (CollectionUtils.isEmpty(notCompleteJobTaskBatchList)) { + TerminalJobPrepareHandler terminalJobPrepareHandler = SpringContext.getBeanByType(TerminalJobPrepareHandler.class); + terminalJobPrepareHandler.handler(prepare); + } else { + for (JobTaskBatch jobTaskBatch : notCompleteJobTaskBatchList) { + prepare.setExecutionAt(jobTaskBatch.getExecutionAt()); + prepare.setTaskBatchId(jobTaskBatch.getId()); + for (JobPrePareHandler prePareHandler : prePareHandlers) { + if (prePareHandler.matches(jobTaskBatch.getTaskStatus())) { + prePareHandler.handler(prepare); + break; + } + } + } + } + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/ScanJobTaskActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/ScanJobTaskActor.java new file mode 100644 index 00000000..13bd2680 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dispatch/ScanJobTaskActor.java @@ -0,0 +1,137 @@ +package com.aizuda.easy.retry.server.job.task.dispatch; + +import akka.actor.AbstractActor; +import akka.actor.ActorRef; +import cn.hutool.core.lang.Assert; +import com.aizuda.easy.retry.common.core.enums.StatusEnum; +import com.aizuda.easy.retry.common.core.log.LogUtils; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.common.cache.CacheConsumerGroup; +import com.aizuda.easy.retry.server.common.dto.PartitionTask; +import com.aizuda.easy.retry.server.common.dto.ScanTask; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.WaitStrategy; +import com.aizuda.easy.retry.server.job.task.dto.JobPartitionTask; +import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; +import java.util.function.Function; + +import static com.aizuda.easy.retry.server.job.task.strategy.WaitStrategies.*; + +/** + * JOB任务扫描 + * + * @author: www.byteblogs.com + * @date : 2023-09-22 09:08 + * @since 2.4.0 + */ +@Component(ActorGenerator.SCAN_JOB_ACTOR) +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@Slf4j +public class ScanJobTaskActor extends AbstractActor { + + @Autowired + private JobMapper jobMapper; + + private static final AtomicLong lastId = new AtomicLong(0L); + + @Override + public Receive createReceive() { + return receiveBuilder().match(ScanTask.class, config -> { + + try { + doScan(config); + } catch (Exception e) { + LogUtils.error(log, "Data scanner processing exception. [{}]", config, e); + } + + }).build(); + + } + + private void doScan(final ScanTask scanTask) { + log.info("job scan start"); + + long total = process(startId -> listAvailableJobs(startId, scanTask), partitionTasks -> { + for (final JobPartitionTask partitionTask : (List) partitionTasks) { + CacheConsumerGroup.addOrUpdate(partitionTask.getGroupName()); + JobTaskPrepareDTO jobTaskPrepare = JobTaskConverter.INSTANCE.toJobTaskPrepare(partitionTask); + + // 更新下次触发时间 + WaitStrategy waitStrategy = WaitStrategyEnum.getWaitStrategy(partitionTask.getTriggerType()); + WaitStrategyContext waitStrategyContext = new WaitStrategyContext(); + waitStrategyContext.setTriggerType(partitionTask.getTriggerType()); + waitStrategyContext.setTriggerInterval(partitionTask.getTriggerInterval()); + waitStrategyContext.setNextTriggerAt(partitionTask.getNextTriggerAt()); + + Job job = new Job(); + job.setId(partitionTask.getId()); + job.setNextTriggerAt(waitStrategy.computeRetryTime(waitStrategyContext)); + Assert.isTrue(1 == jobMapper.updateById(job), + () -> new EasyRetryServerException("更新job下次触发时间失败.jobId:[{}]", job.getId())); + + // 执行预处理阶段 + ActorRef actorRef = ActorGenerator.jobTaskPrepareActor(); + actorRef.tell(jobTaskPrepare, actorRef); + } + }, 0); + + log.info("job scan end. total:[{}]", total); + } + + private List listAvailableJobs(Long startId, ScanTask scanTask) { + + List jobs = jobMapper.selectPage(new PageDTO(0, 1000), + new LambdaQueryWrapper() + .eq(Job::getJobStatus, StatusEnum.YES.getStatus()) + .in(Job::getBucketIndex, scanTask.getBuckets()) + .le(Job::getNextTriggerAt, LocalDateTime.now().plusSeconds(6)) + .eq(Job::getDeleted, StatusEnum.NO.getStatus()) + .gt(Job::getId, startId) + ).getRecords(); + + return JobTaskConverter.INSTANCE.toJobPartitionTasks(jobs); + } + + public long process( + Function> dataSource, Consumer> task, long startId) { + int total = 0; + do { + List products = dataSource.apply(startId); + if (CollectionUtils.isEmpty(products)) { + // 没有查询到数据直接退出 + break; + } + + total += products.size(); + + task.accept(products); + startId = maxId(products); + } while (startId > 0); + + return total; + } + + private static long maxId(List products) { + Optional max = products.stream().map(PartitionTask::getId).max(Long::compareTo); + return max.orElse(-1L) + 1; + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/BaseDTO.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/BaseDTO.java new file mode 100644 index 00000000..75186bed --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/BaseDTO.java @@ -0,0 +1,19 @@ +package com.aizuda.easy.retry.server.job.task.dto; + +import lombok.Data; + +/** + * @author www.byteblogs.com + * @date 2023-10-06 17:05:04 + * @since 2.4.0 + */ +@Data +public class BaseDTO { + + private Long jobId; + private Long taskBatchId; + private String groupName; + private Long taskId; + private Integer taskType; + private String clientId; +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobExecutorResultDTO.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobExecutorResultDTO.java new file mode 100644 index 00000000..26cb15d9 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobExecutorResultDTO.java @@ -0,0 +1,31 @@ +package com.aizuda.easy.retry.server.job.task.dto; + +import lombok.Data; + +/** + * @author www.byteblogs.com + * @date 2023-10-05 17:18:38 + * @since 2.4.0 + */ +@Data +public class JobExecutorResultDTO { + + private Long jobId; + + private Long taskBatchId; + + private Long taskId; + + private String groupName; + + private Integer taskStatus; + + private String message; + + private String clientId; + + private Integer taskType; + + private Object result; + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobLogDTO.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobLogDTO.java new file mode 100644 index 00000000..8809d390 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobLogDTO.java @@ -0,0 +1,44 @@ +package com.aizuda.easy.retry.server.job.task.dto; + +import lombok.Data; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 22:34:14 + * @since 2.4.0 + */ +@Data +public class JobLogDTO { + + /** + * 组名称 + */ + private String groupName; + + /** + * 任务信息id + */ + private Long jobId; + + /** + * 任务实例id + */ + private Long taskBatchId; + + /** + * 调度任务id + */ + private Long taskId; + + /** + * 执行的客户端信息 + */ + private String clientId; + + /** + * 调度信息 + */ + private String message; + + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobPartitionTask.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobPartitionTask.java new file mode 100644 index 00000000..1012de9d --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobPartitionTask.java @@ -0,0 +1,52 @@ +package com.aizuda.easy.retry.server.job.task.dto; + +import com.aizuda.easy.retry.server.common.dto.PartitionTask; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-10 17:52 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class JobPartitionTask extends PartitionTask { + + /** + * 组名称 + */ + private String groupName; + + /** + * 名称 + */ + private String jobName; + + /** + * 下次触发时间 + */ + private LocalDateTime nextTriggerAt; + + /** + * 阻塞策略 1、丢弃 2、覆盖 3、并行 + */ + private Integer blockStrategy; + + /** + * 触发类型 1.CRON 表达式 2. 固定时间 + */ + private Integer triggerType; + + /** + * 间隔时长 + */ + private String triggerInterval; + + /** + * 任务执行超时时间,单位秒 + */ + private Integer executorTimeout; + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobTaskPrepareDTO.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobTaskPrepareDTO.java index 702b462e..635c26ea 100644 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobTaskPrepareDTO.java +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobTaskPrepareDTO.java @@ -24,79 +24,33 @@ public class JobTaskPrepareDTO { */ private String jobName; - /** - * 执行方法参数 - */ - private String argsStr; - - /** - * 参数类型 text/json - */ - private String argsType; - - /** - * 扩展字段 - */ - private String extAttrs; - /** * 下次触发时间 */ private LocalDateTime nextTriggerAt; - /** - * 重试状态 0、关闭、1、开启 - */ - private Integer jobStatus; - - /** - * 执行器路由策略 - */ - private String routeKey; - - /** - * 执行器类型 1、Java - */ - private Integer executorType; - - /** - * 执行器名称 - */ - private String executorName; - - /** - * 触发类型 1.CRON 表达式 2. 固定时间 - */ - private Integer triggerType; - - /** - * 间隔时长 - */ - private String triggerInterval; - /** * 阻塞策略 1、丢弃 2、覆盖 3、并行 */ private Integer blockStrategy; + /** + * 任务类型 + */ + private Integer taskType; + /** * 任务执行超时时间,单位秒 */ private Integer executorTimeout; - /** - * 最大重试次数 - */ - private Integer maxRetryTimes; + private Long taskBatchId; + + private String clientId; /** - * 重试间隔(s) + * 任务执行时间 */ - private Integer retryInterval; - - /** - * bucket - */ - private Integer bucketIndex; + private LocalDateTime executionAt; } diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobTimerTaskDTO.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobTimerTaskDTO.java new file mode 100644 index 00000000..55f7f1f8 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/JobTimerTaskDTO.java @@ -0,0 +1,14 @@ +package com.aizuda.easy.retry.server.job.task.dto; + +import lombok.Data; + +/** + * @author www.byteblogs.com + * @date 2023-09-30 23:19:39 + * @since 2.4.0 + */ +@Data +public class JobTimerTaskDTO { + + private Long taskBatchId; +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/RealJobExecutorDTO.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/RealJobExecutorDTO.java new file mode 100644 index 00000000..027cdf07 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/RealJobExecutorDTO.java @@ -0,0 +1,71 @@ +package com.aizuda.easy.retry.server.job.task.dto; + +import lombok.Data; +import lombok.EqualsAndHashCode; + + +/** + * @author www.byteblogs.com + * @date 2023-10-06 16:45:13 + * @since 2.4.0 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class RealJobExecutorDTO extends BaseDTO { + + private Long jobId; + + /** + * 名称 + */ + private String jobName; + + /** + * 执行方法参数 + */ + private String argsStr; + + /** + * 参数类型 text/json + */ + private String argsType; + + /** + * 扩展字段 + */ + private String extAttrs; + + + private Long taskBatchId; + + private Long taskId; + + private Integer taskType; + + private String groupName; + + private Integer parallelNum; + + private Integer executorType; + + private String executorName; + + private String clientId; + + /** + * 最大重试次数 + */ + private Integer maxRetryTimes; + + /** + * 重试间隔(s) + */ + private Integer retryInterval; + + private Integer shardingTotal; + + private Integer shardingIndex; + + private Integer executorTimeout; + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/RealStopTaskInstanceDTO.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/RealStopTaskInstanceDTO.java new file mode 100644 index 00000000..dc20f0d5 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/RealStopTaskInstanceDTO.java @@ -0,0 +1,20 @@ +package com.aizuda.easy.retry.server.job.task.dto; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-07 10:50 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class RealStopTaskInstanceDTO extends BaseDTO { + + /** + * 下次触发时间 + */ + private LocalDateTime nextTriggerAt; +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/TaskExecuteDTO.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/TaskExecuteDTO.java index 6b9b6e48..ab8f15ed 100644 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/TaskExecuteDTO.java +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/dto/TaskExecuteDTO.java @@ -9,5 +9,7 @@ import lombok.Data; @Data public class TaskExecuteDTO { - private Long taskId; + private Long jobId; + private Long taskBatchId; + private String groupName; } diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/BlockStrategyEnum.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/BlockStrategyEnum.java deleted file mode 100644 index be3ef171..00000000 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/BlockStrategyEnum.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.aizuda.easy.retry.server.job.task.enums; - -/** - * @author www.byteblogs.com - * @date 2023-09-24 12:01:31 - * @since 2.4.0 - */ -public enum BlockStrategyEnum { -} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/TaskStatusEnum.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/TaskStatusEnum.java deleted file mode 100644 index 109c0f77..00000000 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/TaskStatusEnum.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.aizuda.easy.retry.server.job.task.enums; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * @author: www.byteblogs.com - * @date : 2023-09-26 14:26 - */ -@AllArgsConstructor -@Getter -public enum TaskStatusEnum { - - /** - * 待处理 - */ - WAIT(10), - - /** - * 处理中 - */ - PROCESSING(20), - - /** - * 处理中 - */ - PROCESSED_SUCCESS(21), - - /** - * 处理中 - */ - PROCESSED_FAIL(22), - - /** - * 中断中 - */ - INTERRUPTING(30), - - /** - * 中断成功 - */ - INTERRUPT_SUCCESS(31), - - /** - * 中断失败 - */ - INTERRUPT_FAIL(32), - - ; - - private final int status; -} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/TaskTypeEnum.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/TaskTypeEnum.java new file mode 100644 index 00000000..f36681db --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/enums/TaskTypeEnum.java @@ -0,0 +1,31 @@ +package com.aizuda.easy.retry.server.job.task.enums; + +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 10:39:22 + * @since 2.4.0 + */ +@AllArgsConstructor +@Getter +public enum TaskTypeEnum { + + CLUSTER(1), + BROADCAST(2), + SHARDING(3); + + private final int type; + + public static TaskTypeEnum valueOf(int type) { + for (TaskTypeEnum value : TaskTypeEnum.values()) { + if (value.getType() == type) { + return value; + } + } + + throw new EasyRetryServerException("未知类型"); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/executor/JobExecutor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/executor/JobExecutor.java deleted file mode 100644 index 687a5545..00000000 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/executor/JobExecutor.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.aizuda.easy.retry.server.job.task.executor; - -/** - * @author www.byteblogs.com - * @date 2023-09-24 11:40:21 - * @since 2.4.0 - */ -public class JobExecutor { -} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/batch/JobTaskBatchGenerator.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/batch/JobTaskBatchGenerator.java new file mode 100644 index 00000000..5275addc --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/batch/JobTaskBatchGenerator.java @@ -0,0 +1,65 @@ +package com.aizuda.easy.retry.server.job.task.generator.batch; + +import cn.hutool.core.lang.Assert; +import com.aizuda.easy.retry.common.core.enums.JobOperationReasonEnum; +import com.aizuda.easy.retry.server.common.cache.CacheRegisterTable; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.job.task.dto.JobTimerTaskDTO; +import com.aizuda.easy.retry.common.core.enums.JobTaskBatchStatusEnum; +import com.aizuda.easy.retry.server.job.task.handler.timer.JobTimerTask; +import com.aizuda.easy.retry.server.job.task.handler.timer.JobTimerWheelHandler; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskBatchMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTaskBatch; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.time.ZoneId; +import java.util.concurrent.TimeUnit; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 10:22:26 + * @since 2.4.0 + */ +@Component +@Slf4j +public class JobTaskBatchGenerator { + + @Autowired + private JobTaskBatchMapper jobTaskBatchMapper; + + @Transactional + public void generateJobTaskBatch(JobTaskBatchGeneratorContext context) { + + // 生成一个新的任务 + JobTaskBatch jobTaskBatch = new JobTaskBatch(); + jobTaskBatch.setJobId(context.getJobId()); + jobTaskBatch.setGroupName(context.getGroupName()); + + // 无执行的节点 + if (CollectionUtils.isEmpty(CacheRegisterTable.getServerNodeSet(context.getGroupName()))) { + jobTaskBatch.setTaskStatus(JobTaskBatchStatusEnum.CANCEL.getStatus()); + jobTaskBatch.setOperationReason(JobOperationReasonEnum.NOT_CLIENT.getReason()); + Assert.isTrue(1 == jobTaskBatchMapper.insert(jobTaskBatch), () -> new EasyRetryServerException("新增调度任务失败.jobId:[{}]", context.getJobId())); + return; + } + + // 生成一个新的任务 + jobTaskBatch.setTaskStatus(JobTaskBatchStatusEnum.WAITING.getStatus()); + Assert.isTrue(1 == jobTaskBatchMapper.insert(jobTaskBatch), () -> new EasyRetryServerException("新增调度任务失败.jobId:[{}]", context.getJobId())); + + // 进入时间轮 + long delay = context.getNextTriggerAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + - System.currentTimeMillis(); + JobTimerTaskDTO jobTimerTaskDTO = new JobTimerTaskDTO(); + jobTimerTaskDTO.setTaskBatchId(jobTaskBatch.getId()); + + JobTimerWheelHandler.register(context.getGroupName(), context.getJobId(), + new JobTimerTask(jobTimerTaskDTO), delay, TimeUnit.MILLISECONDS); + + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/batch/JobTaskBatchGeneratorContext.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/batch/JobTaskBatchGeneratorContext.java new file mode 100644 index 00000000..95adc7d3 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/batch/JobTaskBatchGeneratorContext.java @@ -0,0 +1,36 @@ +package com.aizuda.easy.retry.server.job.task.generator.batch; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 13:12:48 + * @since 2.4.0 + */ +@Data +public class JobTaskBatchGeneratorContext { + + /** + * 组名称 + */ + private String groupName; + + /** + * 任务id + */ + private Long jobId; + + /** + * 任务类型 + */ + private Integer taskInstanceType; + + /** + * 下次触发时间 + */ + private LocalDateTime nextTriggerAt; + + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/AbstractJobTaskGenerator.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/AbstractJobTaskGenerator.java new file mode 100644 index 00000000..548dab4d --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/AbstractJobTaskGenerator.java @@ -0,0 +1,26 @@ +package com.aizuda.easy.retry.server.job.task.generator.task; + +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import org.springframework.beans.factory.InitializingBean; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 13:08:14 + * @since 2.4.0 + */ +public abstract class AbstractJobTaskGenerator implements JobTaskGenerator, InitializingBean { + + @Override + public List generate(JobTaskGenerateContext context) { + return doGenerate(context); + } + + protected abstract List doGenerate(JobTaskGenerateContext context); + + @Override + public void afterPropertiesSet() throws Exception { + JobTaskGeneratorFactory.registerTaskInstance(getTaskInstanceType(), this); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/BroadcastTaskGenerator.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/BroadcastTaskGenerator.java new file mode 100644 index 00000000..cb0ef15d --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/BroadcastTaskGenerator.java @@ -0,0 +1,73 @@ +package com.aizuda.easy.retry.server.job.task.generator.task; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.aizuda.easy.retry.common.core.enums.JobTaskStatusEnum; +import com.aizuda.easy.retry.server.common.cache.CacheRegisterTable; +import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 21:25:08 + * @since 2.4.0 + */ +@Component +@Slf4j +public class BroadcastTaskGenerator extends AbstractJobTaskGenerator { + + @Autowired + private JobTaskMapper jobTaskMapper; + @Autowired + private JobMapper jobMapper; + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.BROADCAST; + } + + @Override + @Transactional + public List doGenerate(JobTaskGenerateContext context) { + Set serverNodes = CacheRegisterTable.getServerNodeSet(context.getGroupName()); + if (CollectionUtils.isEmpty(serverNodes)) { + log.error("无可执行的客户端信息. jobId:[{}]", context.getJobId()); + return Lists.newArrayList(); + } + + Job job = jobMapper.selectById(context.getJobId()); + + List jobTasks = new ArrayList<>(serverNodes.size()); + for (RegisterNodeInfo serverNode : serverNodes) { + JobTask jobTask = JobTaskConverter.INSTANCE.toJobTaskInstance(context); + jobTask.setClientId(serverNode.getHostId()); + jobTask.setArgsType(job.getArgsType()); + jobTask.setArgsStr(job.getArgsStr()); + jobTask.setExtAttrs(job.getExtAttrs()); + jobTask.setExecuteStatus(JobTaskStatusEnum.RUNNING.getStatus()); + jobTask.setResultMessage(Optional.ofNullable(jobTask.getResultMessage()).orElse(StrUtil.EMPTY)); + Assert.isTrue(1 == jobTaskMapper.insert(jobTask), () -> new EasyRetryServerException("新增任务实例失败")); + jobTasks.add(jobTask); + } + + return jobTasks; + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/ClusterTaskGenerator.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/ClusterTaskGenerator.java new file mode 100644 index 00000000..6f05c85e --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/ClusterTaskGenerator.java @@ -0,0 +1,69 @@ +package com.aizuda.easy.retry.server.job.task.generator.task; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.aizuda.easy.retry.common.core.enums.JobTaskStatusEnum; +import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.common.handler.ClientNodeAllocateHandler; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 12:59:53 + * @since 2.4.0 + */ +@Component +@Slf4j +public class ClusterTaskGenerator extends AbstractJobTaskGenerator { + + @Autowired + protected ClientNodeAllocateHandler clientNodeAllocateHandler; + @Autowired + private JobTaskMapper jobTaskMapper; + @Autowired + private JobMapper jobMapper; + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.CLUSTER; + } + + @Override + public List doGenerate(JobTaskGenerateContext context) { + // 生成可执行任务 + RegisterNodeInfo serverNode = clientNodeAllocateHandler.getServerNode(context.getGroupName()); + if (Objects.isNull(serverNode)) { + log.error("无可执行的客户端信息. jobId:[{}]", context.getJobId()); + return Lists.newArrayList(); + } + + Job job = jobMapper.selectById(context.getJobId()); + + // 新增任务实例 + JobTask jobTask = JobTaskConverter.INSTANCE.toJobTaskInstance(context); + jobTask.setClientId(serverNode.getHostId()); + jobTask.setArgsType(job.getArgsType()); + jobTask.setArgsStr(job.getArgsStr()); + jobTask.setExtAttrs(job.getExtAttrs()); + jobTask.setExecuteStatus(JobTaskStatusEnum.RUNNING.getStatus()); + jobTask.setResultMessage(Optional.ofNullable(jobTask.getResultMessage()).orElse(StrUtil.EMPTY)); + Assert.isTrue(1 == jobTaskMapper.insert(jobTask), () -> new EasyRetryServerException("新增任务实例失败")); + + return Lists.newArrayList(jobTask); + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGenerateContext.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGenerateContext.java new file mode 100644 index 00000000..75eae9d3 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGenerateContext.java @@ -0,0 +1,15 @@ +package com.aizuda.easy.retry.server.job.task.generator.task; + +import lombok.Data; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 13:02:57 + * @since 2.4.0 + */ +@Data +public class JobTaskGenerateContext { + private Long taskBatchId; + private String groupName; + private Long jobId; +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGenerator.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGenerator.java new file mode 100644 index 00000000..8e0f0031 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGenerator.java @@ -0,0 +1,19 @@ +package com.aizuda.easy.retry.server.job.task.generator.task; + +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 10:43:58 + * @since 2.4.0 + */ +public interface JobTaskGenerator { + + TaskTypeEnum getTaskInstanceType(); + + List generate(JobTaskGenerateContext context); + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGeneratorFactory.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGeneratorFactory.java new file mode 100644 index 00000000..ef08a0b8 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/JobTaskGeneratorFactory.java @@ -0,0 +1,23 @@ +package com.aizuda.easy.retry.server.job.task.generator.task; + +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 13:04:09 + * @since 2.4.0 + */ +public class JobTaskGeneratorFactory { + + private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); + + public static void registerTaskInstance(TaskTypeEnum taskInstanceType, JobTaskGenerator generator) { + CACHE.put(taskInstanceType, generator); + } + + public static JobTaskGenerator getTaskInstance(Integer type) { + return CACHE.get(TaskTypeEnum.valueOf(type)); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/ShardingTaskGenerator.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/ShardingTaskGenerator.java new file mode 100644 index 00000000..e34705f6 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/generator/task/ShardingTaskGenerator.java @@ -0,0 +1,80 @@ +package com.aizuda.easy.retry.server.job.task.generator.task; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.aizuda.easy.retry.common.core.enums.JobTaskStatusEnum; +import com.aizuda.easy.retry.server.common.cache.CacheRegisterTable; +import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.common.handler.ClientNodeAllocateHandler; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.*; + +/** + * 分片参数格式 + * 0=参数1;1=参数2; + * + * @author www.byteblogs.com + * @date 2023-10-02 21:37:22 + * @since 2.4.0 + */ +@Component +@Slf4j +public class ShardingTaskGenerator extends AbstractJobTaskGenerator { + + @Autowired + private JobMapper jobMapper; + @Autowired + protected ClientNodeAllocateHandler clientNodeAllocateHandler; + @Autowired + private JobTaskMapper jobTaskMapper; + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.SHARDING; + } + + @Override + public List doGenerate(JobTaskGenerateContext context) { + + Set serverNodes = CacheRegisterTable.getServerNodeSet(context.getGroupName()); + if (CollectionUtils.isEmpty(serverNodes)) { + log.error("无可执行的客户端信息. jobId:[{}]", context.getJobId()); + return Lists.newArrayList(); + } + + Job job = jobMapper.selectById(context.getJobId()); + String argsStr = job.getArgsStr(); + Map split = Splitter.on(";").omitEmptyStrings().withKeyValueSeparator('=').split(argsStr); + + List nodeInfoList = new ArrayList<>(serverNodes); + List jobTasks = new ArrayList<>(split.size()); + split.forEach((key, value) -> { + RegisterNodeInfo registerNodeInfo = nodeInfoList.get(Integer.parseInt(key) % serverNodes.size()); + // 新增任务实例 + JobTask jobTask = JobTaskConverter.INSTANCE.toJobTaskInstance(context); + jobTask.setClientId(registerNodeInfo.getHostId()); + jobTask.setArgsType(job.getArgsType()); + jobTask.setArgsStr(job.getArgsStr()); + jobTask.setExtAttrs(job.getExtAttrs()); + jobTask.setExecuteStatus(JobTaskStatusEnum.RUNNING.getStatus()); + jobTask.setResultMessage(Optional.ofNullable(jobTask.getResultMessage()).orElse(StrUtil.EMPTY)); + Assert.isTrue(1 == jobTaskMapper.insert(jobTask), () -> new EasyRetryServerException("新增任务实例失败")); + }); + + return jobTasks; + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/AbstractClientCallbackHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/AbstractClientCallbackHandler.java new file mode 100644 index 00000000..0e52b769 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/AbstractClientCallbackHandler.java @@ -0,0 +1,25 @@ +package com.aizuda.easy.retry.server.job.task.handler.callback; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 23:12:33 + * @since 2.4.0 + */ +public abstract class AbstractClientCallbackHandler implements ClientCallbackHandler, InitializingBean { + + @Override + @Transactional + public void callback(ClientCallbackContext context) { + doCallback(context); + } + + protected abstract void doCallback(ClientCallbackContext context); + + @Override + public void afterPropertiesSet() throws Exception { + ClientCallbackFactory.registerJobExecutor(getTaskInstanceType(), this); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/BroadcastClientCallbackHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/BroadcastClientCallbackHandler.java new file mode 100644 index 00000000..69e6c3ac --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/BroadcastClientCallbackHandler.java @@ -0,0 +1,40 @@ +package com.aizuda.easy.retry.server.job.task.handler.callback; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobExecutorResultDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Collections; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-07 10:24 + * @since : 2.4.0 + */ +@Component +@Slf4j +public class BroadcastClientCallbackHandler extends AbstractClientCallbackHandler { + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.BROADCAST; + } + + @Override + protected void doCallback(final ClientCallbackContext context) { + JobExecutorResultDTO jobExecutorResultDTO = JobTaskConverter.INSTANCE.toJobExecutorResultDTO(context); + jobExecutorResultDTO.setTaskId(context.getTaskId()); + jobExecutorResultDTO.setMessage(context.getExecuteResult().getMessage()); + jobExecutorResultDTO.setResult(context.getExecuteResult().getResult()); + jobExecutorResultDTO.setTaskType(getTaskInstanceType().getType()); + + ActorRef actorRef = ActorGenerator.jobTaskExecutorResultActor(); + actorRef.tell(jobExecutorResultDTO, actorRef); + + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackContext.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackContext.java new file mode 100644 index 00000000..4da00a90 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackContext.java @@ -0,0 +1,27 @@ +package com.aizuda.easy.retry.server.job.task.handler.callback; + +import com.aizuda.easy.retry.client.model.ExecuteResult; +import lombok.Data; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 23:13:05 + * @since 2.4.0 + */ +@Data +public class ClientCallbackContext { + + private Long jobId; + + private Long taskBatchId; + + private Long taskId; + + private String groupName; + + private Integer taskStatus; + + private ExecuteResult executeResult; + + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackFactory.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackFactory.java new file mode 100644 index 00000000..d5f947d7 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackFactory.java @@ -0,0 +1,23 @@ +package com.aizuda.easy.retry.server.job.task.handler.callback; + +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 13:04:09 + * @since 2.4.0 + */ +public class ClientCallbackFactory { + + private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); + + public static void registerJobExecutor(TaskTypeEnum taskInstanceType, ClientCallbackHandler callbackHandler) { + CACHE.put(taskInstanceType, callbackHandler); + } + + public static ClientCallbackHandler getClientCallback(Integer type) { + return CACHE.get(TaskTypeEnum.valueOf(type)); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackHandler.java new file mode 100644 index 00000000..7543d4e9 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClientCallbackHandler.java @@ -0,0 +1,15 @@ +package com.aizuda.easy.retry.server.job.task.handler.callback; + +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 23:10:50 + * @since 2.4.0 + */ +public interface ClientCallbackHandler { + + TaskTypeEnum getTaskInstanceType(); + + void callback(ClientCallbackContext context); +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClusterClientCallbackHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClusterClientCallbackHandler.java new file mode 100644 index 00000000..578fa618 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ClusterClientCallbackHandler.java @@ -0,0 +1,39 @@ +package com.aizuda.easy.retry.server.job.task.handler.callback; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobExecutorResultDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 23:12:12 + * @since 2.4.0 + */ +@Component +@Slf4j +public class ClusterClientCallbackHandler extends AbstractClientCallbackHandler { + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.CLUSTER; + } + + @Override + protected void doCallback(ClientCallbackContext context) { + + JobExecutorResultDTO jobExecutorResultDTO = JobTaskConverter.INSTANCE.toJobExecutorResultDTO(context); + jobExecutorResultDTO.setTaskId(context.getTaskId()); + jobExecutorResultDTO.setMessage(context.getExecuteResult().getMessage()); + jobExecutorResultDTO.setResult(context.getExecuteResult().getResult()); + jobExecutorResultDTO.setTaskType(getTaskInstanceType().getType()); + + ActorRef actorRef = ActorGenerator.jobTaskExecutorResultActor(); + actorRef.tell(jobExecutorResultDTO, actorRef); + + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ShardingClientCallbackHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ShardingClientCallbackHandler.java new file mode 100644 index 00000000..ec2082a9 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/callback/ShardingClientCallbackHandler.java @@ -0,0 +1,40 @@ +package com.aizuda.easy.retry.server.job.task.handler.callback; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobExecutorResultDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Collections; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-07 10:24 + * @since : 2.4.0 + */ +@Component +@Slf4j +public class ShardingClientCallbackHandler extends AbstractClientCallbackHandler { + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.SHARDING; + } + + @Override + protected void doCallback(final ClientCallbackContext context) { + + JobExecutorResultDTO jobExecutorResultDTO = JobTaskConverter.INSTANCE.toJobExecutorResultDTO(context); + jobExecutorResultDTO.setTaskId(context.getTaskId()); + jobExecutorResultDTO.setMessage(context.getExecuteResult().getMessage()); + jobExecutorResultDTO.setResult(context.getExecuteResult().getResult()); + jobExecutorResultDTO.setTaskType(getTaskInstanceType().getType()); + + ActorRef actorRef = ActorGenerator.jobTaskExecutorResultActor(); + actorRef.tell(jobExecutorResultDTO, actorRef); + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/AbstractJobExecutor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/AbstractJobExecutor.java new file mode 100644 index 00000000..8764bd31 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/AbstractJobExecutor.java @@ -0,0 +1,51 @@ +package com.aizuda.easy.retry.server.job.task.handler.executor; + +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.generator.task.JobTaskGenerateContext; +import com.aizuda.easy.retry.server.job.task.generator.task.JobTaskGenerator; +import com.aizuda.easy.retry.server.job.task.generator.task.JobTaskGeneratorFactory; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 22:13:04 + * @since 2.4.0 + */ +public abstract class AbstractJobExecutor implements JobExecutor, InitializingBean { + + @Autowired + private JobMapper jobMapper; + + @Override + public void execute(JobExecutorContext context) { + + // 生成任务 + JobTaskGenerator taskInstance = JobTaskGeneratorFactory.getTaskInstance(getTaskInstanceType().getType()); + JobTaskGenerateContext instanceGenerateContext = JobTaskConverter.INSTANCE.toJobTaskInstanceGenerateContext(context); + instanceGenerateContext.setTaskBatchId(context.getTaskBatchId()); + List taskList = taskInstance.generate(instanceGenerateContext); + if (CollectionUtils.isEmpty(taskList)) { + return; + } + + Job job = jobMapper.selectById(context.getJobId()); + context.setJob(job); + context.setTaskList(taskList); + + doExecute(context); + } + + protected abstract void doExecute(JobExecutorContext context); + + @Override + public void afterPropertiesSet() throws Exception { + JobExecutorFactory.registerJobExecutor(getTaskInstanceType(), this); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/BroadcastTaskJobExecutor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/BroadcastTaskJobExecutor.java new file mode 100644 index 00000000..b96ac911 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/BroadcastTaskJobExecutor.java @@ -0,0 +1,43 @@ +package com.aizuda.easy.retry.server.job.task.handler.executor; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.RealJobExecutorDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-06 10:27:26 + * @since 2.4.0 + */ +@Component +@Slf4j +public class BroadcastTaskJobExecutor extends AbstractJobExecutor { + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.BROADCAST; + } + + @Override + protected void doExecute(JobExecutorContext context) { + + Job job = context.getJob(); + List taskList = context.getTaskList(); + + for (JobTask jobTask : taskList) { + RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(job, jobTask); + ActorRef actorRef = ActorGenerator.jobRealTaskExecutorActor(); + actorRef.tell(realJobExecutor, actorRef); + } + + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/ClusterJobExecutor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/ClusterJobExecutor.java new file mode 100644 index 00000000..bae67fd3 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/ClusterJobExecutor.java @@ -0,0 +1,42 @@ +package com.aizuda.easy.retry.server.job.task.handler.executor; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.RealJobExecutorDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 22:12:40 + * @since 2.4.0 + */ +@Slf4j +@Component +public class ClusterJobExecutor extends AbstractJobExecutor { + + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.CLUSTER; + } + + @Override + protected void doExecute(JobExecutorContext context) { + + // 调度客户端 + Job job = context.getJob(); + List taskList = context.getTaskList(); + RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(job, taskList.get(0)); + ActorRef actorRef = ActorGenerator.jobRealTaskExecutorActor(); + actorRef.tell(realJobExecutor, actorRef); + + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutor.java new file mode 100644 index 00000000..88ace6ea --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutor.java @@ -0,0 +1,15 @@ +package com.aizuda.easy.retry.server.job.task.handler.executor; + +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; + +/** + * @author www.byteblogs.com + * @date 2023-09-24 11:40:21 + * @since 2.4.0 + */ +public interface JobExecutor { + + TaskTypeEnum getTaskInstanceType(); + + void execute(JobExecutorContext context); +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutorContext.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutorContext.java new file mode 100644 index 00000000..14117133 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutorContext.java @@ -0,0 +1,41 @@ +package com.aizuda.easy.retry.server.job.task.handler.executor; + +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import lombok.Data; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 22:53:49 + * @since 2.4.0 + */ +@Data +public class JobExecutorContext { + + /** + * 组名称 + */ + private String groupName; + + /** + * 任务id + */ + private Long jobId; + + /** + * 任务id + */ + private Long taskBatchId; + + /** + * 任务类型 + */ + private Integer taskType; + + private List taskList; + + private Job job; + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutorFactory.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutorFactory.java new file mode 100644 index 00000000..71181ede --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/JobExecutorFactory.java @@ -0,0 +1,23 @@ +package com.aizuda.easy.retry.server.job.task.handler.executor; + +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 13:04:09 + * @since 2.4.0 + */ +public class JobExecutorFactory { + + private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); + + public static void registerJobExecutor(TaskTypeEnum taskInstanceType, JobExecutor executor) { + CACHE.put(taskInstanceType, executor); + } + + public static JobExecutor getJobExecutor(Integer type) { + return CACHE.get(TaskTypeEnum.valueOf(type)); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/RealJobExecutorActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/RealJobExecutorActor.java new file mode 100644 index 00000000..86be9b81 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/RealJobExecutorActor.java @@ -0,0 +1,142 @@ +package com.aizuda.easy.retry.server.job.task.handler.executor; + +import akka.actor.AbstractActor; +import akka.actor.ActorRef; +import com.aizuda.easy.retry.client.model.request.DispatchJobRequest; +import com.aizuda.easy.retry.common.core.enums.JobTaskStatusEnum; +import com.aizuda.easy.retry.common.core.enums.StatusEnum; +import com.aizuda.easy.retry.common.core.log.LogUtils; +import com.aizuda.easy.retry.common.core.model.Result; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.common.cache.CacheRegisterTable; +import com.aizuda.easy.retry.server.common.client.RequestBuilder; +import com.aizuda.easy.retry.server.common.client.RpcClient; +import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobExecutorResultDTO; +import com.aizuda.easy.retry.server.job.task.dto.JobLogDTO; +import com.aizuda.easy.retry.server.job.task.dto.RealJobExecutorDTO; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.github.rholder.retry.Attempt; +import com.github.rholder.retry.RetryException; +import com.github.rholder.retry.RetryListener; +import com.github.rholder.retry.Retryer; +import com.github.rholder.retry.RetryerBuilder; +import com.github.rholder.retry.StopStrategies; +import com.github.rholder.retry.WaitStrategies; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * @author www.byteblogs.com + * @date 2023-10-06 16:42:08 + * @since 2.4.0 + */ +@Component(ActorGenerator.REAL_JOB_EXECUTOR_ACTOR) +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@Slf4j +public class RealJobExecutorActor extends AbstractActor { + + @Autowired + private JobTaskMapper jobTaskMapper; + + @Override + public Receive createReceive() { + return receiveBuilder().match(RealJobExecutorDTO.class, realJobExecutorDTO -> { + try { + doExecute(realJobExecutorDTO); + } catch (Exception e) { + log.error("请求客户端发生异常", e); + } + }).build(); + } + + private void doExecute(RealJobExecutorDTO realJobExecutorDTO) { + // 检查客户端是否存在 + RegisterNodeInfo registerNodeInfo = CacheRegisterTable.getServerNode(realJobExecutorDTO.getGroupName(), realJobExecutorDTO.getClientId()); + if (Objects.isNull(registerNodeInfo)) { + taskExecuteFailure(realJobExecutorDTO, "无可执行的客户端"); + return; + } + + JobLogDTO jobLogDTO = JobTaskConverter.INSTANCE.toJobLogDTO(realJobExecutorDTO); + DispatchJobRequest dispatchJobRequest = JobTaskConverter.INSTANCE.toDispatchJobRequest(realJobExecutorDTO); + + // 构建重试组件 + Retryer> retryer = buildResultRetryer(realJobExecutorDTO); + + try { + // 构建请求客户端对象 + RpcClient rpcClient = buildRpcClient(registerNodeInfo); + Result dispatch = retryer.call(() -> rpcClient.dispatch(dispatchJobRequest)); + if (dispatch.getStatus() == StatusEnum.YES.getStatus() && Objects.equals(dispatch.getData(), Boolean.TRUE)) { + jobLogDTO.setMessage("任务调度成功"); + } else { + jobLogDTO.setMessage(dispatch.getMessage()); + } + + ActorRef actorRef = ActorGenerator.jobLogActor(); + actorRef.tell(jobLogDTO, actorRef); + } catch (Exception e) { + log.error("调用客户端失败.", e); + Throwable throwable = e; + if (e.getClass().isAssignableFrom(RetryException.class)) { + RetryException re = (RetryException) e; + throwable = re.getLastFailedAttempt().getExceptionCause(); + taskExecuteFailure(realJobExecutorDTO, throwable.getMessage()); + } + } + + } + + private Retryer> buildResultRetryer(RealJobExecutorDTO realJobExecutorDTO) { + Retryer> retryer = RetryerBuilder.>newBuilder() + .retryIfException(throwable -> true) + .withStopStrategy(StopStrategies.stopAfterAttempt(realJobExecutorDTO.getMaxRetryTimes())) + .withWaitStrategy(WaitStrategies.fixedWait(realJobExecutorDTO.getRetryInterval(), TimeUnit.SECONDS)) + .withRetryListener(new RetryListener() { + @Override + public void onRetry(Attempt attempt) { + if (attempt.hasException()) { + LogUtils.error(log, "任务调度失败. taskInstanceId:[{}] count:[{}]", + realJobExecutorDTO.getTaskBatchId(), attempt.getAttemptNumber(), attempt.getExceptionCause()); + JobTask jobTask = new JobTask(); + jobTask.setRetryCount((int) attempt.getAttemptNumber()); + jobTaskMapper.updateById(jobTask); + } + } + }) + .build(); + return retryer; + } + + private RpcClient buildRpcClient(RegisterNodeInfo registerNodeInfo) { + RpcClient rpcClient = RequestBuilder.newBuilder() + .hostPort(registerNodeInfo.getHostPort()) + .groupName(registerNodeInfo.getGroupName()) + .hostId(registerNodeInfo.getHostId()) + .hostIp(registerNodeInfo.getHostIp()) + .contextPath(registerNodeInfo.getContextPath()) + .client(RpcClient.class) + .build(); + return rpcClient; + } + + private static void taskExecuteFailure(RealJobExecutorDTO realJobExecutorDTO, String message) { + ActorRef actorRef = ActorGenerator.jobTaskExecutorResultActor(); + JobExecutorResultDTO jobExecutorResultDTO = new JobExecutorResultDTO(); + jobExecutorResultDTO.setTaskId(realJobExecutorDTO.getTaskBatchId()); + jobExecutorResultDTO.setJobId(realJobExecutorDTO.getJobId()); + jobExecutorResultDTO.setTaskBatchId(realJobExecutorDTO.getTaskBatchId()); + jobExecutorResultDTO.setTaskStatus(JobTaskStatusEnum.FAIL.getStatus()); + jobExecutorResultDTO.setMessage(message); + actorRef.tell(jobExecutorResultDTO, actorRef); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/ShardingJobExecutor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/ShardingJobExecutor.java new file mode 100644 index 00000000..52f2d2ca --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/executor/ShardingJobExecutor.java @@ -0,0 +1,44 @@ +package com.aizuda.easy.retry.server.job.task.handler.executor; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.RealJobExecutorDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.po.Job; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + + * + * @author www.byteblogs.com + * @date 2023-10-06 17:33:51 + * @since 2.4.0 + */ +@Component +@Slf4j +public class ShardingJobExecutor extends AbstractJobExecutor { + + @Override + public TaskTypeEnum getTaskInstanceType() { + return TaskTypeEnum.SHARDING; + } + + @Override + protected void doExecute(JobExecutorContext context) { + Job job = context.getJob(); + List taskList = context.getTaskList(); + for (int i = 0; i < taskList.size(); i++) { + RealJobExecutorDTO realJobExecutor = JobTaskConverter.INSTANCE.toRealJobExecutorDTO(job, taskList.get(i)); + realJobExecutor.setShardingIndex(i); + realJobExecutor.setShardingTotal(taskList.size()); + ActorRef actorRef = ActorGenerator.jobRealTaskExecutorActor(); + actorRef.tell(realJobExecutor, actorRef); + } + + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/helper/JobTaskBatchHelper.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/helper/JobTaskBatchHelper.java new file mode 100644 index 00000000..88605a0c --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/helper/JobTaskBatchHelper.java @@ -0,0 +1,53 @@ +package com.aizuda.easy.retry.server.job.task.handler.helper; + +import com.aizuda.easy.retry.common.core.enums.JobTaskBatchStatusEnum; +import com.aizuda.easy.retry.common.core.enums.JobTaskStatusEnum; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskBatchMapper; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTaskBatch; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-10 16:50 + */ +@Component +public class JobTaskBatchHelper { + + @Autowired + private JobTaskMapper jobTaskMapper; + @Autowired + private JobTaskBatchMapper jobTaskBatchMapper; + + public void complete(Long taskBatchId) { + + List jobTasks = jobTaskMapper.selectList( + new LambdaQueryWrapper().select(JobTask::getExecuteStatus) + .eq(JobTask::getTaskBatchId, taskBatchId)); + + if (jobTasks.stream().anyMatch(jobTask -> JobTaskStatusEnum.NOT_COMPLETE.contains(jobTask.getExecuteStatus()))) { + return; + } + + long failCount = jobTasks.stream().filter(jobTask -> jobTask.getExecuteStatus() == JobTaskBatchStatusEnum.FAIL.getStatus()).count(); + long stopCount = jobTasks.stream().filter(jobTask -> jobTask.getExecuteStatus() == JobTaskBatchStatusEnum.STOP.getStatus()).count(); + + JobTaskBatch jobTaskBatch = new JobTaskBatch(); + jobTaskBatch.setId(taskBatchId); + if (failCount > 0) { + jobTaskBatch.setTaskStatus(JobTaskBatchStatusEnum.FAIL.getStatus()); + } else if (stopCount > 0) { + jobTaskBatch.setTaskStatus(JobTaskBatchStatusEnum.STOP.getStatus()); + } else { + jobTaskBatch.setTaskStatus(JobTaskBatchStatusEnum.SUCCESS.getStatus()); + } + + jobTaskBatchMapper.updateById(jobTaskBatch); + + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/AbstractJobPrePareHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/AbstractJobPrePareHandler.java new file mode 100644 index 00000000..bb959c7b --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/AbstractJobPrePareHandler.java @@ -0,0 +1,19 @@ +package com.aizuda.easy.retry.server.job.task.handler.prepare; + +import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 09:57:55 + * @since 2.4.0 + */ +public abstract class AbstractJobPrePareHandler implements JobPrePareHandler { + + @Override + public void handler(JobTaskPrepareDTO jobPrepareDTO) { + + doHandler(jobPrepareDTO); + } + + protected abstract void doHandler(JobTaskPrepareDTO jobPrepareDTO); +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/JobPrePareHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/JobPrePareHandler.java new file mode 100644 index 00000000..20ee7eee --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/JobPrePareHandler.java @@ -0,0 +1,15 @@ +package com.aizuda.easy.retry.server.job.task.handler.prepare; + +import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 09:34:00 + * @since 2.4.0 + */ +public interface JobPrePareHandler { + + boolean matches(Integer status); + + void handler(JobTaskPrepareDTO jobPrepareDTO); +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/RunningJobPrepareHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/RunningJobPrepareHandler.java new file mode 100644 index 00000000..e1280fd4 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/RunningJobPrepareHandler.java @@ -0,0 +1,62 @@ +package com.aizuda.easy.retry.server.job.task.handler.prepare; + +import com.aizuda.easy.retry.common.core.enums.JobTaskBatchStatusEnum; +import com.aizuda.easy.retry.server.job.task.BlockStrategy; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; +import com.aizuda.easy.retry.server.job.task.handler.helper.JobTaskBatchHelper; +import com.aizuda.easy.retry.server.job.task.strategy.BlockStrategies; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskBatchMapper; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.time.ZoneId; + +/** + * 处理处于{@link JobTaskBatchStatusEnum::RUNNING}状态的任务 + * + * @author www.byteblogs.com + * @date 2023-10-05 18:29:22 + * @since 2.4.0 + */ +@Component +@Slf4j +public class RunningJobPrepareHandler extends AbstractJobPrePareHandler { + + @Autowired + private JobTaskBatchHelper jobTaskBatchHelper; + + @Override + public boolean matches(Integer status) { + return JobTaskBatchStatusEnum.RUNNING.getStatus() == status; + } + + @Override + protected void doHandler(JobTaskPrepareDTO prepare) { + log.info("存在运行中的任务. taskBatchId:[{}]", prepare.getTaskBatchId()); + + // 若存在所有的任务都是完成,但是批次上的状态为运行中,则是并发导致的未把批次状态变成为终态,此处做一次兜底处理 + jobTaskBatchHelper.complete(prepare.getTaskBatchId()); + + // 计算超时时间 + long delay = System.currentTimeMillis() - prepare.getExecutionAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + + int blockStrategy = prepare.getBlockStrategy(); + // 计算超时时间,到达超时时间覆盖任务 + if (delay > prepare.getExecutorTimeout() * 1000) { + log.info("任务执行超时.taskBatchId:[{}] delay:[{}] executorTimeout:[{}]", prepare.getTaskBatchId(), delay, prepare.getExecutorTimeout() * 1000); + blockStrategy = BlockStrategies.BlockStrategyEnum.OVERLAY.getBlockStrategy(); + } + + BlockStrategies.BlockStrategyContext blockStrategyContext = JobTaskConverter.INSTANCE.toBlockStrategyContext(prepare); + BlockStrategy blockStrategyInterface = BlockStrategies.BlockStrategyEnum.getBlockStrategy(blockStrategy); + blockStrategyInterface.block(blockStrategyContext); + + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/TerminalJobPrepareHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/TerminalJobPrepareHandler.java new file mode 100644 index 00000000..78602c3b --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/TerminalJobPrepareHandler.java @@ -0,0 +1,42 @@ +package com.aizuda.easy.retry.server.job.task.handler.prepare; + +import com.aizuda.easy.retry.common.core.enums.JobTaskBatchStatusEnum; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; +import com.aizuda.easy.retry.server.job.task.generator.batch.JobTaskBatchGenerator; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +/** + * 处理处于已完成 {@link JobTaskBatchStatusEnum::COMPLETED} 状态的任务 + * + * @author www.byteblogs.com + * @date 2023-10-02 10:16:28 + * @since 2.4.0 + */ +@Order(Ordered.HIGHEST_PRECEDENCE) +@Component +@Slf4j +public class TerminalJobPrepareHandler extends AbstractJobPrePareHandler { + + @Autowired + private JobTaskBatchGenerator jobTaskBatchGenerator; + + @Override + public boolean matches(Integer status) { + return Objects.isNull(status); + } + + @Override + protected void doHandler(JobTaskPrepareDTO jobPrepareDTO) { + log.info("无处理中的数据. jobId:[{}]", jobPrepareDTO.getJobId()); + + // 生成任务批次 + jobTaskBatchGenerator.generateJobTaskBatch(JobTaskConverter.INSTANCE.toJobTaskGeneratorContext(jobPrepareDTO)); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/WaitJobPrepareHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/WaitJobPrepareHandler.java new file mode 100644 index 00000000..4e3d8ff7 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/prepare/WaitJobPrepareHandler.java @@ -0,0 +1,48 @@ +package com.aizuda.easy.retry.server.job.task.handler.prepare; + +import com.aizuda.easy.retry.common.core.enums.JobTaskBatchStatusEnum; +import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; +import com.aizuda.easy.retry.server.job.task.dto.JobTimerTaskDTO; +import com.aizuda.easy.retry.server.job.task.handler.timer.JobTimerWheelHandler; +import com.aizuda.easy.retry.server.job.task.handler.timer.JobTimerTask; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.time.ZoneId; +import java.util.concurrent.TimeUnit; + +/** + * 处理处于{@link JobTaskBatchStatusEnum::WAIT}状态的任务 + * + * @author www.byteblogs.com + * @date 2023-10-05 18:29:22 + * @since 2.4.0 + */ +@Component +@Slf4j +public class WaitJobPrepareHandler extends AbstractJobPrePareHandler { + + @Override + public boolean matches(Integer status) { + return JobTaskBatchStatusEnum.WAITING.getStatus() == status; + } + + @Override + protected void doHandler(JobTaskPrepareDTO jobPrepareDTO) { + log.info("存在待处理任务. taskBatchId:[{}]", jobPrepareDTO.getTaskBatchId()); + + // 若时间轮中数据不存在则重新加入 + if (!JobTimerWheelHandler.isExisted(jobPrepareDTO.getGroupName(), jobPrepareDTO.getJobId())) { + + // 进入时间轮 + long delay = jobPrepareDTO.getNextTriggerAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() + - System.currentTimeMillis(); + JobTimerTaskDTO jobTimerTaskDTO = new JobTimerTaskDTO(); + jobTimerTaskDTO.setTaskBatchId(jobPrepareDTO.getTaskBatchId()); + + JobTimerWheelHandler.register(jobPrepareDTO.getGroupName(), jobPrepareDTO.getJobId(), + new JobTimerTask(jobTimerTaskDTO), delay, TimeUnit.MILLISECONDS); + } + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/request/ReportDispatchResultPostHttpRequestHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/request/ReportDispatchResultPostHttpRequestHandler.java new file mode 100644 index 00000000..13bb255a --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/request/ReportDispatchResultPostHttpRequestHandler.java @@ -0,0 +1,64 @@ +package com.aizuda.easy.retry.server.job.task.handler.request; + +import cn.hutool.core.net.url.UrlQuery; +import com.aizuda.easy.retry.client.model.request.DispatchJobResultRequest; +import com.aizuda.easy.retry.common.core.enums.StatusEnum; +import com.aizuda.easy.retry.common.core.log.LogUtils; +import com.aizuda.easy.retry.common.core.model.EasyRetryRequest; +import com.aizuda.easy.retry.common.core.model.NettyResult; +import com.aizuda.easy.retry.common.core.util.JsonUtil; +import com.aizuda.easy.retry.server.common.handler.PostHttpRequestHandler; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.handler.callback.ClientCallbackContext; +import com.aizuda.easy.retry.server.job.task.handler.callback.ClientCallbackFactory; +import com.aizuda.easy.retry.server.job.task.handler.callback.ClientCallbackHandler; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import static com.aizuda.easy.retry.common.core.constant.SystemConstants.HTTP_PATH.REPORT_JOB_DISPATCH_RESULT; + +/** + * @author www.byteblogs.com + * @date 2023-09-30 23:01:58 + * @since 2.4.0 + */ +@Slf4j +@Component +public class ReportDispatchResultPostHttpRequestHandler extends PostHttpRequestHandler { + + @Override + public boolean supports(String path) { + return REPORT_JOB_DISPATCH_RESULT.equals(path); + } + + @Override + public HttpMethod method() { + return HttpMethod.POST; + } + + @Override + public String doHandler(String content, UrlQuery query, HttpHeaders headers) { + LogUtils.info(log, "Client Callback Request. content:[{}]", content); + + EasyRetryRequest retryRequest = JsonUtil.parseObject(content, EasyRetryRequest.class); + Object[] args = retryRequest.getArgs(); + + DispatchJobResultRequest dispatchJobResultRequest = JsonUtil.parseObject(JsonUtil.toJsonString(args[0]), DispatchJobResultRequest.class); + + ClientCallbackHandler clientCallback = ClientCallbackFactory.getClientCallback(dispatchJobResultRequest.getTaskType()); + + ClientCallbackContext context = JobTaskConverter.INSTANCE.toClientCallbackContext(dispatchJobResultRequest); + clientCallback.callback(context); + +// JobLogDTO jobLogDTO = JobTaskConverter.INSTANCE.toJobLogDTO(dispatchJobResultRequest); +// ExecuteResult executeResult = dispatchJobResultRequest.getExecuteResult(); +// jobLogDTO.setMessage(executeResult.getMessage()); +// jobLogDTO.setClientId(hostId); +// ActorRef actorRef = ActorGenerator.jobLogActor(); +// actorRef.tell(jobLogDTO, actorRef); + + return JsonUtil.toJsonString(new NettyResult(StatusEnum.YES.getStatus(), "Report Dispatch Result Processed Successfully", Boolean.TRUE, retryRequest.getReqId())); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/AbstractJobTaskStopHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/AbstractJobTaskStopHandler.java new file mode 100644 index 00000000..5861d42e --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/AbstractJobTaskStopHandler.java @@ -0,0 +1,63 @@ +package com.aizuda.easy.retry.server.job.task.handler.stop; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.common.core.enums.JobTaskStatusEnum; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.JobExecutorResultDTO; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-03 09:48:10 + * @since 2.4.0 + */ +public abstract class AbstractJobTaskStopHandler implements JobTaskStopHandler, InitializingBean { + + @Autowired + private JobTaskMapper jobTaskMapper; + + @Override + public void stop(TaskStopJobContext context) { + + List jobTasks = jobTaskMapper.selectList( + new LambdaQueryWrapper() + .eq(JobTask::getTaskBatchId, context.getTaskBatchId()) + .eq(JobTask::getExecuteStatus, JobTaskStatusEnum.NOT_COMPLETE) + ); + + if (CollectionUtils.isEmpty(jobTasks)) { + return; + } + + context.setJobTasks(jobTasks); + + doStop(context); + + if (context.isNeedUpdateTaskStatus()) { + for (final JobTask jobTask : jobTasks) { + JobExecutorResultDTO jobExecutorResultDTO = JobTaskConverter.INSTANCE.toJobExecutorResultDTO(jobTask); + jobExecutorResultDTO.setTaskStatus(JobTaskStatusEnum.STOP.getStatus()); + jobExecutorResultDTO.setMessage("任务停止成功"); + jobExecutorResultDTO.setTaskType(getTaskType().getType()); + ActorRef actorRef = ActorGenerator.jobTaskExecutorResultActor(); + actorRef.tell(jobExecutorResultDTO, actorRef); + } + + } + } + + protected abstract void doStop(TaskStopJobContext context); + + @Override + public void afterPropertiesSet() throws Exception { + JobTaskStopFactory.registerTaskStop(getTaskType(), this); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/BroadcastTaskStopHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/BroadcastTaskStopHandler.java new file mode 100644 index 00000000..daefe320 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/BroadcastTaskStopHandler.java @@ -0,0 +1,43 @@ +package com.aizuda.easy.retry.server.job.task.handler.stop; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.common.handler.ClientNodeAllocateHandler; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.RealStopTaskInstanceDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 12:59:53 + * @since 2.4.0 + */ +@Component +@Slf4j +public class BroadcastTaskStopHandler extends AbstractJobTaskStopHandler { + + @Override + public TaskTypeEnum getTaskType() { + return TaskTypeEnum.BROADCAST; + } + + @Override + public void doStop(TaskStopJobContext context) { + + for (final JobTask jobTask : context.getJobTasks()) { + String clientId = jobTask.getClientId(); + RealStopTaskInstanceDTO taskInstanceDTO = JobTaskConverter.INSTANCE.toRealStopTaskInstanceDTO(context); + taskInstanceDTO.setClientId(clientId); + + ActorRef actorRef = ActorGenerator.jobRealStopTaskInstanceActor(); + actorRef.tell(taskInstanceDTO, actorRef); + } + + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/ClusterTaskStopHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/ClusterTaskStopHandler.java new file mode 100644 index 00000000..13a6b356 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/ClusterTaskStopHandler.java @@ -0,0 +1,51 @@ +package com.aizuda.easy.retry.server.job.task.handler.stop; + +import akka.actor.ActorRef; +import cn.hutool.core.lang.Assert; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.common.handler.ClientNodeAllocateHandler; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.RealStopTaskInstanceDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 12:59:53 + * @since 2.4.0 + */ +@Component +@Slf4j +public class ClusterTaskStopHandler extends AbstractJobTaskStopHandler { + + + @Override + public TaskTypeEnum getTaskType() { + return TaskTypeEnum.CLUSTER; + } + + @Override + public void doStop(TaskStopJobContext context) { + List jobTasks = context.getJobTasks(); + + String clientId = jobTasks.get(0).getClientId(); + RealStopTaskInstanceDTO taskInstanceDTO = JobTaskConverter.INSTANCE.toRealStopTaskInstanceDTO(context); + taskInstanceDTO.setClientId(clientId); + + ActorRef actorRef = ActorGenerator.jobRealStopTaskInstanceActor(); + actorRef.tell(taskInstanceDTO, actorRef); + + } + + + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/JobTaskStopFactory.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/JobTaskStopFactory.java new file mode 100644 index 00000000..eedf410d --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/JobTaskStopFactory.java @@ -0,0 +1,23 @@ +package com.aizuda.easy.retry.server.job.task.handler.stop; + +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 13:04:09 + * @since 2.4.0 + */ +public class JobTaskStopFactory { + + private static final ConcurrentHashMap CACHE = new ConcurrentHashMap<>(); + + public static void registerTaskStop(TaskTypeEnum taskInstanceType, JobTaskStopHandler interrupt) { + CACHE.put(taskInstanceType, interrupt); + } + + public static JobTaskStopHandler getJobTaskStop(Integer type) { + return CACHE.get(TaskTypeEnum.valueOf(type)); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/JobTaskStopHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/JobTaskStopHandler.java new file mode 100644 index 00000000..0e1e0340 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/JobTaskStopHandler.java @@ -0,0 +1,16 @@ +package com.aizuda.easy.retry.server.job.task.handler.stop; + +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 10:43:58 + * @since 2.4.0 + */ +public interface JobTaskStopHandler { + + TaskTypeEnum getTaskType(); + + void stop(TaskStopJobContext context); + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/RealStopTaskActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/RealStopTaskActor.java new file mode 100644 index 00000000..8e481801 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/RealStopTaskActor.java @@ -0,0 +1,66 @@ +package com.aizuda.easy.retry.server.job.task.handler.stop; + +import akka.actor.AbstractActor; +import com.aizuda.easy.retry.client.model.StopJobDTO; +import com.aizuda.easy.retry.common.core.model.Result; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.common.cache.CacheRegisterTable; +import com.aizuda.easy.retry.server.common.client.RequestBuilder; +import com.aizuda.easy.retry.server.common.client.RpcClient; +import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; +import com.aizuda.easy.retry.server.job.task.dto.RealStopTaskInstanceDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +/** + * @author: www.byteblogs.com + * @date : 2023-10-07 10:45 + * @since : 2.4.0 + */ +@Component(ActorGenerator.REAL_STOP_TASK_INSTANCE_ACTOR) +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +@Slf4j +public class RealStopTaskActor extends AbstractActor { + + @Override + public Receive createReceive() { + return receiveBuilder().match(RealStopTaskInstanceDTO.class, realStopTaskInstanceDTO -> { + try { + doStop(realStopTaskInstanceDTO); + } catch (Exception e) { + log.error("停止任务执行失败", e); + } + }).build(); + } + + private void doStop(final RealStopTaskInstanceDTO realStopTaskInstanceDTO) { + + // 检查客户端是否存在 + RegisterNodeInfo registerNodeInfo = CacheRegisterTable.getServerNode(realStopTaskInstanceDTO.getGroupName(), realStopTaskInstanceDTO.getClientId()); + if (Objects.nonNull(registerNodeInfo)) { + // 不用关心停止的结果,若服务端尝试终止失败,客户端会兜底进行关闭 + requestClient(realStopTaskInstanceDTO, registerNodeInfo); + } + } + + private Result requestClient(RealStopTaskInstanceDTO realStopTaskInstanceDTO, RegisterNodeInfo registerNodeInfo) { + RpcClient rpcClient = RequestBuilder.newBuilder() + .hostPort(registerNodeInfo.getHostPort()) + .groupName(realStopTaskInstanceDTO.getGroupName()) + .hostId(registerNodeInfo.getHostId()) + .hostIp(registerNodeInfo.getHostIp()) + .contextPath(registerNodeInfo.getContextPath()) + .client(RpcClient.class) + .build(); + + StopJobDTO stopJobDTO = new StopJobDTO(); + stopJobDTO.setTaskId(realStopTaskInstanceDTO.getTaskBatchId()); + stopJobDTO.setJobId(realStopTaskInstanceDTO.getJobId()); + stopJobDTO.setGroupName(realStopTaskInstanceDTO.getGroupName()); + return rpcClient.stop(stopJobDTO); + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/ShardingTaskStopHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/ShardingTaskStopHandler.java new file mode 100644 index 00000000..caa50b66 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/ShardingTaskStopHandler.java @@ -0,0 +1,40 @@ +package com.aizuda.easy.retry.server.job.task.handler.stop; + +import akka.actor.ActorRef; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.dto.RealStopTaskInstanceDTO; +import com.aizuda.easy.retry.server.job.task.enums.TaskTypeEnum; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 12:59:53 + * @since 2.4.0 + */ +@Component +@Slf4j +public class ShardingTaskStopHandler extends AbstractJobTaskStopHandler { + + @Override + public TaskTypeEnum getTaskType() { + return TaskTypeEnum.SHARDING; + } + + @Override + public void doStop(TaskStopJobContext context) { + + for (final JobTask jobTask : context.getJobTasks()) { + String clientId = jobTask.getClientId(); + RealStopTaskInstanceDTO taskInstanceDTO = JobTaskConverter.INSTANCE.toRealStopTaskInstanceDTO(context); + taskInstanceDTO.setClientId(clientId); + + ActorRef actorRef = ActorGenerator.jobRealStopTaskInstanceActor(); + actorRef.tell(taskInstanceDTO, actorRef); + } + + } + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/TaskStopJobContext.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/TaskStopJobContext.java new file mode 100644 index 00000000..49197fe2 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/stop/TaskStopJobContext.java @@ -0,0 +1,49 @@ +package com.aizuda.easy.retry.server.job.task.handler.stop; + +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * @author www.byteblogs.com + * @date 2023-10-02 22:53:49 + * @since 2.4.0 + */ +@Data +public class TaskStopJobContext { + + /** + * 组名称 + */ + private String groupName; + + /** + * 任务id + */ + private Long jobId; + + /** + * 任务id + */ + private Long taskBatchId; + + /** + * 任务类型 + */ + private Integer taskType; + + /** + * 下次触发时间 + */ + private LocalDateTime nextTriggerAt; + + /** + * 是否需要变更任务状态 + */ + private boolean needUpdateTaskStatus; + + private List jobTasks; + +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/timer/JobTimerTask.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/timer/JobTimerTask.java new file mode 100644 index 00000000..01027034 --- /dev/null +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/timer/JobTimerTask.java @@ -0,0 +1,80 @@ +package com.aizuda.easy.retry.server.job.task.handler.timer; + +import akka.actor.ActorRef; +import cn.hutool.core.lang.Assert; +import com.aizuda.easy.retry.common.core.context.SpringContext; +import com.aizuda.easy.retry.common.core.enums.JobTaskBatchStatusEnum; +import com.aizuda.easy.retry.server.common.akka.ActorGenerator; +import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; +import com.aizuda.easy.retry.server.job.task.dto.JobTimerTaskDTO; +import com.aizuda.easy.retry.server.job.task.dto.TaskExecuteDTO; +import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskBatchMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.JobTaskBatch; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDateTime; +import java.util.Objects; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * @author: www.byteblogs.com + * @date : 2023-09-25 17:28 + * @since 2.4.0 + */ +@AllArgsConstructor +@Slf4j +public class JobTimerTask implements TimerTask { + + private JobTimerTaskDTO jobTimerTaskDTO; + + private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 10, TimeUnit.SECONDS, + new LinkedBlockingQueue<>()); + + @Override + public void run(final Timeout timeout) throws Exception { + // 执行任务调度 + log.info("开始执行任务调度. 当前时间:[{}] taskId:[{}]", LocalDateTime.now(), jobTimerTaskDTO.getTaskBatchId()); + + executor.execute(() -> { + Long jobId = 0L; + String groupName = ""; + try { + JobTaskBatchMapper jobTaskBatchMapper = SpringContext.getBeanByType(JobTaskBatchMapper.class); + JobTaskBatch jobTaskBatch = jobTaskBatchMapper.selectOne(new LambdaQueryWrapper() + .select(JobTaskBatch::getJobId, JobTaskBatch::getGroupName, JobTaskBatch::getId) + .eq(JobTaskBatch::getId, jobTimerTaskDTO.getTaskBatchId()) + .eq(JobTaskBatch::getTaskStatus, JobTaskBatchStatusEnum.WAITING.getStatus())); + if (Objects.isNull(jobTaskBatch)) { + return; + } + + jobId = jobTaskBatch.getJobId(); + groupName = jobTaskBatch.getGroupName(); + jobTaskBatch.setExecutionAt(LocalDateTime.now()); + jobTaskBatch.setTaskStatus(JobTaskBatchStatusEnum.RUNNING.getStatus()); + Assert.isTrue(1 == jobTaskBatchMapper.updateById(jobTaskBatch), + () -> new EasyRetryServerException("更新任务失败")); + + TaskExecuteDTO taskExecuteDTO = new TaskExecuteDTO(); + taskExecuteDTO.setTaskBatchId(jobTimerTaskDTO.getTaskBatchId()); + taskExecuteDTO.setGroupName(groupName); + taskExecuteDTO.setJobId(jobId); + ActorRef actorRef = ActorGenerator.jobTaskExecutorActor(); + actorRef.tell(taskExecuteDTO, actorRef); + } catch (Exception e) { + log.error("任务调度执行失败", e); + } finally { + // 清除时间轮的缓存 + JobTimerWheelHandler.clearCache(groupName, jobId); + } + + }); + + } +} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTimerWheelHandler.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/timer/JobTimerWheelHandler.java similarity index 73% rename from easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTimerWheelHandler.java rename to easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/timer/JobTimerWheelHandler.java index f43d7229..7ebbce90 100644 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTimerWheelHandler.java +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/handler/timer/JobTimerWheelHandler.java @@ -1,4 +1,4 @@ -package com.aizuda.easy.retry.server.job.task.scan; +package com.aizuda.easy.retry.server.job.task.handler.timer; import cn.hutool.core.util.StrUtil; import com.aizuda.easy.retry.common.core.log.LogUtils; @@ -34,7 +34,7 @@ public class JobTimerWheelHandler implements Lifecycle { // tickDuration 和 timeUnit 一格的时间长度 // ticksPerWheel 一圈有多少格 timer = new HashedWheelTimer( - new CustomizableThreadFactory("jop-task-timer-wheel-"), 100, + new CustomizableThreadFactory("job-task-timer-wheel-"), 100, TimeUnit.MILLISECONDS, 1024); timer.start(); @@ -45,7 +45,7 @@ public class JobTimerWheelHandler implements Lifecycle { .build(); } - public static void register(String groupName, String uniqueId, TimerTask task, long delay, TimeUnit unit) { + public static void register(String groupName, Long taskId, TimerTask task, long delay, TimeUnit unit) { if (delay < 0) { delay = 0; @@ -54,36 +54,37 @@ public class JobTimerWheelHandler implements Lifecycle { // TODO 支持可配置 if (delay > 60 * 1000) { LogUtils.warn(log, "距离下次执行时间过久, 不满足进入时间轮的条件. groupName:[{}] uniqueId:[{}] delay:[{}ms]", - groupName, uniqueId, delay); + groupName, taskId, delay); return; } - Timeout timeout = getTimeout(groupName, uniqueId); + Timeout timeout = getTimeout(groupName, taskId); if (Objects.isNull(timeout)) { try { + log.info("加入时间轮. delay:[{}ms] taskId:[{}]", delay, taskId); timeout = timer.newTimeout(task, delay, unit); - cache.put(getKey(groupName, uniqueId), timeout); + cache.put(getKey(groupName, taskId), timeout); } catch (Exception e) { LogUtils.error(log, "加入时间轮失败. groupName:[{}] uniqueId:[{}]", - groupName, uniqueId, e); + groupName, taskId, e); } } } - private static String getKey(String groupName, String uniqueId) { - return groupName.concat(StrUtil.UNDERLINE).concat(uniqueId); + private static String getKey(String groupName, Long uniqueId) { + return groupName.concat(StrUtil.UNDERLINE).concat(uniqueId.toString()); } - public static Timeout getTimeout(String groupName, String uniqueId) { + public static Timeout getTimeout(String groupName, Long uniqueId) { return cache.getIfPresent(getKey(groupName, uniqueId)); } - public static boolean isExisted(String groupName, String uniqueId) { + public static boolean isExisted(String groupName, Long uniqueId) { return Objects.nonNull(cache.getIfPresent(getKey(groupName, uniqueId))); } - public static boolean cancel(String groupName, String uniqueId) { + public static boolean cancel(String groupName, Long uniqueId) { String key = getKey(groupName, uniqueId); Timeout timeout = cache.getIfPresent(key); if (Objects.isNull(timeout)) { @@ -94,7 +95,7 @@ public class JobTimerWheelHandler implements Lifecycle { return timeout.cancel(); } - public static void clearCache(String groupName, String uniqueId) { + public static void clearCache(String groupName, Long uniqueId) { cache.invalidate(getKey(groupName, uniqueId)); } diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobContext.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobContext.java deleted file mode 100644 index 8e32793a..00000000 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobContext.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.aizuda.easy.retry.server.job.task.scan; - -import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; -import lombok.Data; - -/** - * @author: www.byteblogs.com - * @date : 2023-09-25 17:35 - */ -@Data -public class JobContext { - - private RegisterNodeInfo registerNodeInfo; - -} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobExecutorActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobExecutorActor.java deleted file mode 100644 index fd7cdeec..00000000 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobExecutorActor.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.aizuda.easy.retry.server.job.task.scan; - -import akka.actor.AbstractActor; -import akka.actor.ActorRef; -import com.aizuda.easy.retry.client.model.DispatchJobDTO; -import com.aizuda.easy.retry.common.core.log.LogUtils; -import com.aizuda.easy.retry.common.core.model.Result; -import com.aizuda.easy.retry.server.common.akka.ActorGenerator; -import com.aizuda.easy.retry.server.common.cache.CacheRegisterTable; -import com.aizuda.easy.retry.server.common.client.RequestBuilder; -import com.aizuda.easy.retry.server.common.client.RpcClient; -import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; -import com.aizuda.easy.retry.server.job.task.dto.TaskExecuteDTO; -import com.aizuda.easy.retry.template.datasource.access.AccessTemplate; -import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; -import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -/** - * @author: www.byteblogs.com - * @date : 2023-09-25 17:41 - */ -@Component(ActorGenerator.JOB_EXECUTOR_ACTOR) -@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) -@Slf4j -public class JobExecutorActor extends AbstractActor { - - @Autowired - private JobTaskMapper jobTaskMapper; - - @Override - public Receive createReceive() { - return receiveBuilder().match(TaskExecuteDTO.class, taskExecute -> { - try { - doExecute(taskExecute); - } catch (Exception e) { - LogUtils.error(log, "job executor exception. [{}]", taskExecute, e); - } - }).build(); - } - - private void doExecute(final TaskExecuteDTO taskExecute) { - // 调度客户端 - JobTask jobTask = jobTaskMapper.selectById(taskExecute.getTaskId()); - RegisterNodeInfo registerNodeInfo = CacheRegisterTable.getServerNode(jobTask.getGroupName(), jobTask.getHostId()); - RpcClient rpcClient = RequestBuilder.newBuilder() - .hostPort(registerNodeInfo.getHostPort()) - .groupName(registerNodeInfo.getGroupName()) - .hostId(registerNodeInfo.getHostId()) - .hostIp(registerNodeInfo.getHostIp()) - .contextPath(registerNodeInfo.getContextPath()) - .client(RpcClient.class) - .build(); - - DispatchJobDTO dispatchJobDTO = new DispatchJobDTO(); - dispatchJobDTO.setJobId(jobTask.getJobId()); - dispatchJobDTO.setTaskId(jobTask.getId()); - dispatchJobDTO.setGroupName(jobTask.getGroupName()); - Result dispatch = rpcClient.dispatch(dispatchJobDTO); - - } -} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTaskPrepareActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTaskPrepareActor.java deleted file mode 100644 index 6111f612..00000000 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTaskPrepareActor.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.aizuda.easy.retry.server.job.task.scan; - -import akka.actor.AbstractActor; -import cn.hutool.core.lang.Assert; -import com.aizuda.easy.retry.server.common.akka.ActorGenerator; -import com.aizuda.easy.retry.server.common.cache.CacheRegisterTable; -import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; -import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; -import com.aizuda.easy.retry.server.common.handler.ClientNodeAllocateHandler; -import com.aizuda.easy.retry.server.job.task.BlockStrategy; -import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; -import com.aizuda.easy.retry.server.job.task.enums.TaskStatusEnum; -import com.aizuda.easy.retry.server.job.task.strategy.BlockStrategies; -import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper; -import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; -import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -import java.time.ZoneId; -import java.util.Objects; -import java.util.concurrent.TimeUnit; - -/** - * 调度任务准备阶段 - * - * @author www.byteblogs.com - * @date 2023-09-25 22:20:53 - * @since - */ -@Component(ActorGenerator.SCAN_JOB_ACTOR) -@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) -@Slf4j -public class JobTaskPrepareActor extends AbstractActor { - - @Autowired - private JobMapper jobMapper; - @Autowired - private JobTaskMapper jobTaskMapper; - @Autowired - protected ClientNodeAllocateHandler clientNodeAllocateHandler; - - @Override - public Receive createReceive() { - return receiveBuilder().match(JobTaskPrepareDTO.class, job -> { - try { - doPrepare(job); - } catch (Exception e) { - - } - }).build(); - } - - private void doPrepare(JobTaskPrepareDTO prepare) { - - JobTask jobTask = jobTaskMapper.selectOne(new LambdaQueryWrapper() - .eq(JobTask::getJobId, prepare.getJobId()) - .in(JobTask::getTaskStatus, - TaskStatusEnum.WAIT.getStatus(), TaskStatusEnum.INTERRUPTING.getStatus(), - TaskStatusEnum.INTERRUPTING.getStatus())); - if (Objects.isNull(jobTask)) { - // 生成可执行任务 - RegisterNodeInfo serverNode = clientNodeAllocateHandler.getServerNode(prepare.getGroupName()); - if (Objects.isNull(serverNode)) { - log.error("无可执行的客户端信息. jobId:[{}]", prepare.getJobId()); - return; - } - - jobTask = new JobTask(); - jobTask.setHostId(serverNode.getHostId()); - jobTask.setJobId(prepare.getJobId()); - jobTask.setGroupName(prepare.getGroupName()); - Assert.isTrue(1 == jobTaskMapper.insert(jobTask), - () -> new EasyRetryServerException("新增调度任务失败.jobId:[{}]", prepare.getJobId())); - - // 进入时间轮 - JobContext jobContext = new JobContext(); - jobContext.setRegisterNodeInfo(serverNode); - long delay = prepare.getNextTriggerAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - - System.currentTimeMillis(); - JobTimerWheelHandler.register(prepare.getGroupName(), prepare.getJobId().toString(), - new JobTimerTask(jobTask.getId(), jobTask.getGroupName()), delay, TimeUnit.MILLISECONDS); - } else { - - BlockStrategies.BlockStrategyContext blockStrategyContext = new BlockStrategies.BlockStrategyContext(); - blockStrategyContext.setRegisterNodeInfo(CacheRegisterTable.getServerNode(jobTask.getGroupName(), jobTask.getHostId())); - BlockStrategy blockStrategy = BlockStrategies.BlockStrategyEnum.getBlockStrategy( - prepare.getBlockStrategy()); - blockStrategy.block(blockStrategyContext); - } - - - } -} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTimerTask.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTimerTask.java deleted file mode 100644 index b23da9e9..00000000 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/JobTimerTask.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.aizuda.easy.retry.server.job.task.scan; - -import akka.actor.ActorRef; -import com.aizuda.easy.retry.server.common.akka.ActorGenerator; -import com.aizuda.easy.retry.server.job.task.dto.TaskExecuteDTO; -import io.netty.util.Timeout; -import io.netty.util.TimerTask; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDateTime; - -/** - * @author: www.byteblogs.com - * @date : 2023-09-25 17:28 - */ -@AllArgsConstructor -@Slf4j -public class JobTimerTask implements TimerTask { - - private Long taskId; - private String groupName; - - @Override - public void run(final Timeout timeout) throws Exception { - // 执行任务调度 - log.info("开始执行任务调度. 当前时间:[{}]", LocalDateTime.now()); - - // 先清除时间轮的缓存 - JobTimerWheelHandler.clearCache(groupName, taskId.toString()); - - TaskExecuteDTO taskExecuteDTO = new TaskExecuteDTO(); - ActorRef actorRef = ActorGenerator.jobTaskExecutorActor(); - actorRef.tell(taskExecuteDTO, actorRef); - } -} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/ScanJobTaskActor.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/ScanJobTaskActor.java deleted file mode 100644 index 5eef4fb1..00000000 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/scan/ScanJobTaskActor.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.aizuda.easy.retry.server.job.task.scan; - -import akka.actor.AbstractActor; -import akka.actor.ActorRef; -import cn.hutool.core.lang.Assert; -import com.aizuda.easy.retry.common.core.enums.StatusEnum; -import com.aizuda.easy.retry.common.core.log.LogUtils; -import com.aizuda.easy.retry.server.common.akka.ActorGenerator; -import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; -import com.aizuda.easy.retry.server.common.dto.ScanTask; -import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; -import com.aizuda.easy.retry.server.common.handler.ClientNodeAllocateHandler; -import com.aizuda.easy.retry.server.job.task.BlockStrategy; -import com.aizuda.easy.retry.server.job.task.WaitStrategy; -import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO; -import com.aizuda.easy.retry.server.job.task.strategy.BlockStrategies; -import com.aizuda.easy.retry.server.job.task.strategy.BlockStrategies.BlockStrategyContext; -import com.aizuda.easy.retry.server.job.task.strategy.BlockStrategies.BlockStrategyEnum; -import com.aizuda.easy.retry.server.job.task.strategy.WaitStrategies; -import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper; -import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; -import com.aizuda.easy.retry.template.datasource.persistence.po.Job; -import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; -import com.aizuda.easy.retry.template.datasource.persistence.po.RetryTask; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; -import io.netty.util.Timeout; -import io.netty.util.TimerTask; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import static com.aizuda.easy.retry.server.job.task.strategy.WaitStrategies.*; - -/** - * JOB任务扫描 - * - * @author: www.byteblogs.com - * @date : 2023-09-22 09:08 - * @since 2.4.0 - */ -@Component(ActorGenerator.SCAN_JOB_ACTOR) -@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) -@Slf4j -public class ScanJobTaskActor extends AbstractActor { - - @Autowired - private JobMapper jobMapper; - @Autowired - private JobTaskMapper jobTaskMapper; - @Autowired - protected ClientNodeAllocateHandler clientNodeAllocateHandler; - - private static final AtomicLong lastId = new AtomicLong(0L); - - @Override - public Receive createReceive() { - return receiveBuilder().match(ScanTask.class, config -> { - - try { - doScan(config); - } catch (Exception e) { - LogUtils.error(log, "Data scanner processing exception. [{}]", config, e); - } - - }).build(); - - } - - private void doScan(final ScanTask scanTask) { - - List jobs = listAvailableJobs(lastId.get()); - if (CollectionUtils.isEmpty(jobs)) { - // 数据为空则休眠5s - try { - Thread.sleep((10 / 2) * 1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - - // 重置最大id - lastId.set(0L); - return; - } - - lastId.set(jobs.get(jobs.size() - 1).getId()); - - for (Job job : jobs) { - - // 更新下次触发时间 - WaitStrategy waitStrategy = WaitStrategyEnum.getWaitStrategy(job.getTriggerType()); - WaitStrategyContext waitStrategyContext = new WaitStrategyContext(); - waitStrategyContext.setTriggerType(job.getTriggerType()); - waitStrategyContext.setTriggerInterval(job.getTriggerInterval()); - waitStrategyContext.setNextTriggerAt(job.getNextTriggerAt()); - job.setNextTriggerAt(waitStrategy.computeRetryTime(waitStrategyContext)); - Assert.isTrue(1 == jobMapper.updateById(job), () -> new EasyRetryServerException("更新job下次触发时间失败.jobId:[{}]", job.getId())); - - // 执行预处理阶段 - ActorRef actorRef = ActorGenerator.jobTaskPrepareActor(); - JobTaskPrepareDTO jobTaskPrepareDTO = new JobTaskPrepareDTO(); - jobTaskPrepareDTO.setJobId(job.getId()); - jobTaskPrepareDTO.setTriggerType(job.getTriggerType()); - jobTaskPrepareDTO.setNextTriggerAt(job.getNextTriggerAt()); - actorRef.tell(jobTaskPrepareDTO, actorRef); - } - - } - - private List listAvailableJobs(Long lastId) { - return jobMapper.selectPage(new PageDTO(0, 1000), - new LambdaQueryWrapper() - .eq(Job::getJobStatus, StatusEnum.YES.getStatus()) - // TODO 提前10秒把需要执行的任务拉取出来 - .le(Job::getNextTriggerAt, LocalDateTime.now().plusSeconds(10)) - .eq(Job::getDeleted, StatusEnum.NO.getStatus()) - .gt(Job::getId, lastId) - ).getRecords(); - } -} diff --git a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/strategy/BlockStrategies.java b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/strategy/BlockStrategies.java index 2d28b7bb..32653176 100644 --- a/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/strategy/BlockStrategies.java +++ b/easy-retry-server/easy-retry-server-job-task/src/main/java/com/aizuda/easy/retry/server/job/task/strategy/BlockStrategies.java @@ -1,28 +1,19 @@ package com.aizuda.easy.retry.server.job.task.strategy; -import cn.hutool.core.lang.Assert; -import com.aizuda.easy.retry.client.model.InterruptJobDTO; import com.aizuda.easy.retry.common.core.context.SpringContext; -import com.aizuda.easy.retry.common.core.enums.StatusEnum; -import com.aizuda.easy.retry.common.core.model.Result; -import com.aizuda.easy.retry.server.common.client.RequestBuilder; -import com.aizuda.easy.retry.server.common.client.RpcClient; -import com.aizuda.easy.retry.server.common.dto.RegisterNodeInfo; import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException; import com.aizuda.easy.retry.server.job.task.BlockStrategy; -import com.aizuda.easy.retry.server.job.task.enums.TaskStatusEnum; -import com.aizuda.easy.retry.server.job.task.scan.JobContext; -import com.aizuda.easy.retry.server.job.task.scan.JobTimerTask; -import com.aizuda.easy.retry.server.job.task.scan.JobTimerWheelHandler; -import com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper; -import com.aizuda.easy.retry.template.datasource.persistence.po.Job; -import com.aizuda.easy.retry.template.datasource.persistence.po.JobTask; +import com.aizuda.easy.retry.server.job.task.JobTaskConverter; +import com.aizuda.easy.retry.server.job.task.generator.batch.JobTaskBatchGenerator; +import com.aizuda.easy.retry.server.job.task.generator.batch.JobTaskBatchGeneratorContext; +import com.aizuda.easy.retry.server.job.task.handler.stop.JobTaskStopHandler; +import com.aizuda.easy.retry.server.job.task.handler.stop.JobTaskStopFactory; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import java.util.concurrent.TimeUnit; +import java.time.LocalDateTime; /** * @author: www.byteblogs.com @@ -62,85 +53,53 @@ public class BlockStrategies { private String groupName; - private RegisterNodeInfo registerNodeInfo; + /** + * 任务类型 + */ + private Integer taskType; + + /** + * 下次触发时间 + */ + private LocalDateTime nextTriggerAt; + } private static final class DiscardBlockStrategy implements BlockStrategy { @Override - public boolean block(final BlockStrategyContext context) { + public void block(final BlockStrategyContext context) { log.warn("阻塞策略为丢弃此次执行. jobId:[{}]", context.getJobId()); - return false; } } private static final class OverlayBlockStrategy implements BlockStrategy { @Override - public boolean block(final BlockStrategyContext context) { + public void block(final BlockStrategyContext context) { log.warn("阻塞策略为覆盖. jobId:[{}]", context.getJobId()); - // 向客户端发送中断执行指令 - RegisterNodeInfo registerNodeInfo = context.registerNodeInfo; - RpcClient rpcClient = RequestBuilder.newBuilder() - .hostPort(registerNodeInfo.getHostPort()) - .groupName(registerNodeInfo.getGroupName()) - .hostId(registerNodeInfo.getHostId()) - .hostIp(registerNodeInfo.getHostIp()) - .contextPath(registerNodeInfo.getContextPath()) - .client(RpcClient.class) - .build(); - InterruptJobDTO interruptJobDTO = new InterruptJobDTO(); - interruptJobDTO.setTaskId(context.getTaskId()); - interruptJobDTO.setGroupName(context.getGroupName()); - interruptJobDTO.setJobId(context.getJobId()); + // 停止任务 + JobTaskStopHandler instanceInterrupt = JobTaskStopFactory.getJobTaskStop(context.taskType); + instanceInterrupt.stop(JobTaskConverter.INSTANCE.toStopJobContext(context)); - // TODO 处理结果 - Result result = rpcClient.interrupt(interruptJobDTO); - Integer taskStatus; - if (result.getStatus() == StatusEnum.YES.getStatus() && Boolean.TRUE.equals(result.getData())) { - taskStatus = TaskStatusEnum.INTERRUPT_SUCCESS.getStatus(); - - // 生成一个新的任务 - JobTask jobTask = new JobTask(); - jobTask.setJobId(context.getJobId()); - jobTask.setGroupName(context.getGroupName()); - JobTaskMapper jobTaskMapper = SpringContext.getBeanByType(JobTaskMapper.class); - Assert.isTrue(1 == jobTaskMapper.insert(jobTask), () -> new EasyRetryServerException("新增调度任务失败.jobId:[{}]", context.getJobId())); - - JobContext jobContext = new JobContext(); - // 进入时间轮 - JobTimerWheelHandler.register(context.getGroupName(), context.getJobId().toString(), new JobTimerTask(jobTask.getJobId(), jobTask.getGroupName()), 1, TimeUnit.MILLISECONDS); - - } else { - taskStatus = TaskStatusEnum.INTERRUPT_FAIL.getStatus(); - } - - JobTaskMapper jobTaskMapper = SpringContext.getBeanByType(JobTaskMapper.class); - JobTask jobTask = new JobTask(); - jobTask.setTaskStatus(taskStatus); - Assert.isTrue(1 == jobTaskMapper.updateById(jobTask), ()-> new EasyRetryServerException("更新调度任务失败. jopId:[{}]", context.getJobId())); - - return true; + // 重新生成任务 + JobTaskBatchGenerator jobTaskBatchGenerator = SpringContext.getBeanByType(JobTaskBatchGenerator.class); + JobTaskBatchGeneratorContext jobTaskBatchGeneratorContext = JobTaskConverter.INSTANCE.toJobTaskGeneratorContext(context); + jobTaskBatchGenerator.generateJobTaskBatch(jobTaskBatchGeneratorContext); } } private static final class ConcurrencyBlockStrategy implements BlockStrategy { @Override - public boolean block(final BlockStrategyContext context) { + public void block(final BlockStrategyContext context) { log.warn("阻塞策略为并行执行. jobId:[{}]", context.getJobId()); - JobTask jobTask = new JobTask(); - jobTask.setJobId(context.getJobId()); - jobTask.setGroupName(context.getGroupName()); - JobTaskMapper jobTaskMapper = SpringContext.getBeanByType(JobTaskMapper.class); - Assert.isTrue(1 == jobTaskMapper.insert(jobTask), () -> new EasyRetryServerException("新增调度任务失败.jobId:[{}]", context.getJobId())); - - // 进入时间轮 - JobTimerWheelHandler.register(context.getGroupName(), context.getJobId().toString(), new JobTimerTask(jobTask.getJobId(), jobTask.getGroupName()), 1, TimeUnit.MILLISECONDS); - - return false; + // 重新生成任务 + JobTaskBatchGenerator jobTaskBatchGenerator = SpringContext.getBeanByType(JobTaskBatchGenerator.class); + JobTaskBatchGeneratorContext jobTaskBatchGeneratorContext = JobTaskConverter.INSTANCE.toJobTaskGeneratorContext(context); + jobTaskBatchGenerator.generateJobTaskBatch(jobTaskBatchGeneratorContext); } } diff --git a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/AbstractSchedule.java b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/AbstractSchedule.java index 04e6e145..853af4cb 100644 --- a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/AbstractSchedule.java +++ b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/AbstractSchedule.java @@ -59,11 +59,11 @@ public abstract class AbstractSchedule implements Schedule { protected abstract void doExecute(); - abstract String lockName(); + protected abstract String lockName(); - abstract String lockAtMost(); + protected abstract String lockAtMost(); - abstract String lockAtLeast(); + protected abstract String lockAtLeast(); private LockProvider getLockAccess() { return lockProviders.stream() diff --git a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/OfflineNodeSchedule.java b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/OfflineNodeSchedule.java index fdb74995..02b0b9fc 100644 --- a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/OfflineNodeSchedule.java +++ b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/OfflineNodeSchedule.java @@ -59,17 +59,17 @@ public class OfflineNodeSchedule extends AbstractSchedule implements Lifecycle { } @Override - String lockName() { + public String lockName() { return "clearOfflineNode"; } @Override - String lockAtMost() { + public String lockAtMost() { return "PT10S"; } @Override - String lockAtLeast() { + public String lockAtLeast() { return "PT5S"; } diff --git a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryErrorMoreThresholdAlarmSchedule.java b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryErrorMoreThresholdAlarmSchedule.java index 829516f4..8a0dbd22 100644 --- a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryErrorMoreThresholdAlarmSchedule.java +++ b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryErrorMoreThresholdAlarmSchedule.java @@ -93,17 +93,17 @@ public class RetryErrorMoreThresholdAlarmSchedule extends AbstractSchedule imple } @Override - String lockName() { + public String lockName() { return "retryErrorMoreThreshold"; } @Override - String lockAtMost() { + public String lockAtMost() { return "PT10M"; } @Override - String lockAtLeast() { + public String lockAtLeast() { return "PT1M"; } } diff --git a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryTaskMoreThresholdAlarmSchedule.java b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryTaskMoreThresholdAlarmSchedule.java index f24dde1f..6fa28355 100644 --- a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryTaskMoreThresholdAlarmSchedule.java +++ b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryTaskMoreThresholdAlarmSchedule.java @@ -88,17 +88,17 @@ public class RetryTaskMoreThresholdAlarmSchedule extends AbstractSchedule implem } @Override - String lockName() { + public String lockName() { return "retryTaskMoreThreshold"; } @Override - String lockAtMost() { + public String lockAtMost() { return "PT10M"; } @Override - String lockAtLeast() { + public String lockAtLeast() { return "PT1M"; } } diff --git a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryTaskSchedule.java b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryTaskSchedule.java index 5d50750e..4cf1b066 100644 --- a/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryTaskSchedule.java +++ b/easy-retry-server/easy-retry-server-retry-task/src/main/java/com/aizuda/easy/retry/server/retry/task/support/schedule/RetryTaskSchedule.java @@ -52,17 +52,17 @@ public class RetryTaskSchedule extends AbstractSchedule implements Lifecycle { } @Override - String lockName() { + public String lockName() { return "clearFinishAndMoveDeadLetterRetryTask"; } @Override - String lockAtMost() { + public String lockAtMost() { return "PT60s"; } @Override - String lockAtLeast() { + public String lockAtLeast() { return "PT60s"; } } diff --git a/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/EasyRetryServerApplication.java b/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/EasyRetryServerApplication.java index 85afa361..69ab7d44 100644 --- a/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/EasyRetryServerApplication.java +++ b/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/EasyRetryServerApplication.java @@ -2,12 +2,9 @@ package com.aizuda.easy.retry.server; import com.aizuda.easy.retry.server.server.NettyHttpServer; import lombok.extern.slf4j.Slf4j; -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.TaskScheduler; diff --git a/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/dispatch/ConsumerBucketActor.java b/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/dispatch/ConsumerBucketActor.java index ae91c30c..011d7943 100644 --- a/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/dispatch/ConsumerBucketActor.java +++ b/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/dispatch/ConsumerBucketActor.java @@ -13,6 +13,7 @@ import com.aizuda.easy.retry.server.common.dto.ScanTask; import com.aizuda.easy.retry.server.retry.task.support.cache.CacheGroupRateLimiter; import com.aizuda.easy.retry.template.datasource.access.AccessTemplate; import com.aizuda.easy.retry.template.datasource.persistence.mapper.ServerNodeMapper; +import com.aizuda.easy.retry.template.datasource.persistence.po.GroupConfig; import com.aizuda.easy.retry.template.datasource.persistence.po.SceneConfig; import com.aizuda.easy.retry.template.datasource.persistence.po.ServerNode; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -23,8 +24,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -65,27 +68,28 @@ public class ConsumerBucketActor extends AbstractActor { private void doDispatch(final ConsumerBucket consumerBucket) { // 查询桶对应组信息 - Set groupNameSet = accessTemplate.getSceneConfigAccess().list( - new LambdaQueryWrapper().select(SceneConfig::getGroupName) - .eq(SceneConfig::getSceneStatus, StatusEnum.YES.getStatus()) - .in(SceneConfig::getBucketIndex, consumerBucket.getBuckets()) - .groupBy(SceneConfig::getGroupName)).stream().map(SceneConfig::getGroupName).collect(Collectors.toSet()); + List groupConfigs = accessTemplate.getGroupConfigAccess().list( + new LambdaQueryWrapper() + .select(GroupConfig::getGroupName) + .eq(GroupConfig::getGroupStatus, StatusEnum.YES.getStatus()) + .in(GroupConfig::getBucketIndex, consumerBucket.getBuckets()) + ); - // todo 需要对groupNameSet进行状态过滤只有开启才进行任务调度 - // todo 通过同步线程对集群中的当前节点需要处理的组进行同步 - for (final String groupName : groupNameSet) { - CacheConsumerGroup.addOrUpdate(groupName); - ScanTask scanTask = new ScanTask(); - scanTask.setBuckets(consumerBucket.getBuckets()); - scanTask.setGroupName(groupName); - produceScanActorTask(scanTask); + if (!CollectionUtils.isEmpty(groupConfigs)) { + for (final GroupConfig groupConfig : groupConfigs) { + CacheConsumerGroup.addOrUpdate(groupConfig.getGroupName()); + ScanTask scanTask = new ScanTask(); + scanTask.setGroupName(groupConfig.getGroupName()); + scanTask.setBuckets(consumerBucket.getBuckets()); + produceScanActorTask(scanTask); + } } - // job + // 扫描回调数据 ScanTask scanTask = new ScanTask(); scanTask.setBuckets(consumerBucket.getBuckets()); - ActorRef jobActor = TaskTypeEnum.JOB.getActorRef().get(); - jobActor.tell(scanTask, jobActor); + ActorRef scanJobActorRef = cacheActorRef("DEFAULT_JOB_KEY", TaskTypeEnum.JOB); + scanJobActorRef.tell(scanTask, scanJobActorRef); } /** diff --git a/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/dispatch/DispatchService.java b/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/dispatch/DispatchService.java index 0ba4746c..b37bad13 100644 --- a/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/dispatch/DispatchService.java +++ b/easy-retry-server/easy-retry-server-starter/src/main/java/com/aizuda/easy/retry/server/dispatch/DispatchService.java @@ -35,7 +35,7 @@ public class DispatchService implements Lifecycle { /** * 调度时长 */ - public static final Long PERIOD = 10L; + public static final Long PERIOD = 60L; /** * 延迟10s为了尽可能保障集群节点都启动完成在进行rebalance diff --git a/pom.xml b/pom.xml index 16e206ad..3e6134f4 100644 --- a/pom.xml +++ b/pom.xml @@ -105,6 +105,11 @@ easy-retry-client-core ${revision} + + com.aizuda + easy-retry-client-job-core + ${revision} + com.aliyun