feat:动态定时任务开发
This commit is contained in:
@@ -13,6 +13,5 @@ public interface AdminJobClient {
|
||||
|
||||
List<JobConfigDO> fetchJobByAppName(String appName, Long namespace);
|
||||
List<JobConfigDO> fetchJobByAppNameAndVersion(String appName, Integer version, Long namespace);
|
||||
|
||||
void registerJob(JobDefinition jobDefinition, String className);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.xiang.core.schedule.api;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import com.xiang.core.quartz.model.XxzJobProperties;
|
||||
import com.xiang.quartz.common.api.DynamicTaskApi;
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskQueryRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskSaveRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskUpdateRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.response.DynamicTaskInfoResponse;
|
||||
import com.xiang.quartz.common.enums.url.DynamicTaskUrlEnum;
|
||||
import com.xiang.xmc.service.http.helper.BaseHttpHelp;
|
||||
import com.xiang.xmc.service.http.helper.HttpHelperFactory;
|
||||
import com.xiang.xservice.basic.common.resp.Result;
|
||||
import com.xiang.xservice.basic.common.resp.ResultUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: xiang
|
||||
* @Date: 2026-02-11 10:04
|
||||
*/
|
||||
@Service()
|
||||
@RequiredArgsConstructor
|
||||
public class HttpDynamicTaskClientImpl implements DynamicTaskApi {
|
||||
private final XxzJobProperties xxzJobProperties;
|
||||
private static final BaseHttpHelp httpHelp = HttpHelperFactory.createQuartzHttp();
|
||||
|
||||
@Override
|
||||
public Result<Void> saveTask(DynamicTaskSaveRequest request) {
|
||||
String baseUrl = xxzJobProperties.getAdminAddress();
|
||||
String resp = httpHelp.doPost(baseUrl + DynamicTaskUrlEnum.SAVE_TASK.getUrl(), null, JSON.toJSONString(request));
|
||||
return ResultUtils.getData(resp, new TypeReference<Result<Void>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Void> updateTask(DynamicTaskUpdateRequest request) {
|
||||
String baseUrl = xxzJobProperties.getAdminAddress();
|
||||
String resp = httpHelp.doPost(baseUrl + DynamicTaskUrlEnum.UPDATE_TASK.getUrl(), null, JSON.toJSONString(request));
|
||||
return ResultUtils.getData(resp, new TypeReference<Result<Void>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<DynamicTaskInfoResponse> info(Long id) {
|
||||
String baseUrl = xxzJobProperties.getAdminAddress();
|
||||
String resp = httpHelp.doGet(baseUrl + DynamicTaskUrlEnum.QUERY_TASK_INFO.getUrl() + id, null);
|
||||
return ResultUtils.getData(resp, new TypeReference<Result<DynamicTaskInfoResponse>>() {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<List<DynamicTaskInfoResponse>> list(DynamicTaskQueryRequest request) {
|
||||
String baseUrl = xxzJobProperties.getAdminAddress();
|
||||
String resp = httpHelp.doPost(baseUrl + DynamicTaskUrlEnum.QUERY_TASK_LIST.getUrl(), null, JSON.toJSONString(request));
|
||||
return ResultUtils.getData(resp, new TypeReference<Result<List<DynamicTaskInfoResponse>>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.xiang.core.schedule.config;
|
||||
|
||||
import com.xiang.core.schedule.core.DynamicTaskScheduler;
|
||||
import com.xiang.core.schedule.core.TaskRegistry;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@AutoConfiguration
|
||||
@Import({DynamicTaskSchedulerConfig.class, DynamicTaskScheduler.class, TaskRegistry.class})
|
||||
public class DynamicSchedulerAutoConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.xiang.core.schedule.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
@Configuration
|
||||
public class DynamicTaskSchedulerConfig {
|
||||
@Bean
|
||||
public ThreadPoolTaskScheduler globalTaskScheduler() {
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.setPoolSize(10);
|
||||
scheduler.setThreadNamePrefix("dynamic-task-");
|
||||
scheduler.setWaitForTasksToCompleteOnShutdown(true);
|
||||
scheduler.setAwaitTerminationSeconds(30);
|
||||
scheduler.initialize();
|
||||
return scheduler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.xiang.core.schedule.core;
|
||||
|
||||
import com.xiang.core.schedule.entity.TaskConfig;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DynamicTaskScheduler {
|
||||
private final ThreadPoolTaskScheduler taskScheduler;
|
||||
private final Map<Long, ScheduledFuture<?>> taskMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public void schedule(TaskConfig config, Runnable task) {
|
||||
schedule(config, task, LocalDateTime.now());
|
||||
}
|
||||
|
||||
public void schedule(TaskConfig config, Runnable task, LocalDateTime serverTime) {
|
||||
LocalDateTime time = config.getExecutionTime();
|
||||
if (time.isBefore(serverTime)) return;
|
||||
|
||||
ScheduledFuture<?> future = taskScheduler.schedule(() -> {
|
||||
try {
|
||||
task.run();
|
||||
} finally {
|
||||
taskMap.remove(config.getTaskId());
|
||||
}
|
||||
}, Date.from(time.atZone(ZoneId.systemDefault()).toInstant()));
|
||||
taskMap.put(config.getTaskId(), future);
|
||||
}
|
||||
|
||||
public void cancel(Long taskId) {
|
||||
ScheduledFuture<?> future = taskMap.get(taskId);
|
||||
if (future != null) {
|
||||
future.cancel(true);
|
||||
taskMap.remove(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean contains(Long taskId) {
|
||||
return taskMap.containsKey(taskId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.xiang.core.schedule.core;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class TaskRegistry {
|
||||
private final ConcurrentHashMap<Long, Consumer<Long>> handlers = new ConcurrentHashMap<>();
|
||||
|
||||
public void register(Long taskId, Consumer<Long> consumer) {
|
||||
handlers.put(taskId, consumer);
|
||||
}
|
||||
|
||||
public void run(Long taskId) {
|
||||
Consumer<Long> consumer = handlers.get(taskId);
|
||||
if (consumer != null) consumer.accept(taskId);
|
||||
}
|
||||
|
||||
public void unregister(Long taskId) {
|
||||
handlers.remove(taskId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.xiang.core.schedule.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TaskConfig {
|
||||
private Long taskId;
|
||||
private String taskName;
|
||||
private String taskGroup;
|
||||
private LocalDateTime executionTime;
|
||||
private Map<String, Object> parameters;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.xiang.core.schedule.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum TaskGroupEnum {
|
||||
SERVICE_SAMPLE_SCHEDULE("sample", "测试动态定时任务"),
|
||||
SERVICE_FWD_SCHEDULE("xs-fwd", "芬玩岛定时任务");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
TaskGroupEnum(String code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.xiang.core.schedule.helper;
|
||||
|
||||
|
||||
import com.xiang.core.schedule.entity.TaskConfig;
|
||||
|
||||
public interface TaskExecutor {
|
||||
void execute(TaskConfig taskInfo);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.xiang.core.schedule.service;
|
||||
|
||||
import com.xiang.quartz.common.api.DynamicTaskApi;
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskQueryRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskSaveRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskUpdateRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.response.DynamicTaskInfoResponse;
|
||||
import com.xiang.quartz.common.enums.TaskStatusEnum;
|
||||
import com.xiang.xservice.basic.common.resp.Result;
|
||||
import com.xiang.xservice.basic.common.resp.ResultUtils;
|
||||
import com.xiang.xservice.basic.exception.BusinessException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DynamicTaskSchedulerServiceImpl implements IDynamicTaskSchedulerService{
|
||||
|
||||
private final DynamicTaskApi dynamicTaskApi;
|
||||
|
||||
@Override
|
||||
public Boolean saveTask(DynamicTaskSaveRequest entity) {
|
||||
Result<Void> result = dynamicTaskApi.saveTask(entity);
|
||||
if (StringUtils.equals(Result.SUCCESS_CODE, result.getCode())) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateTask(DynamicTaskUpdateRequest entity) {
|
||||
Result<Void> result = dynamicTaskApi.updateTask(entity);
|
||||
if (StringUtils.equals(Result.SUCCESS_CODE, result.getCode())) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicTaskInfoResponse getTask(Long taskId) {
|
||||
return ResultUtils.getData(dynamicTaskApi.info(taskId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateProcess(Long taskId) {
|
||||
DynamicTaskInfoResponse task = getTask(taskId);
|
||||
if (Objects.isNull(task)) {
|
||||
throw new BusinessException("task不存在!");
|
||||
}
|
||||
DynamicTaskUpdateRequest dynamicTaskUpdateRequest = buildUpdateTaskRequest(task);
|
||||
dynamicTaskUpdateRequest.setStatus(TaskStatusEnum.PROCEED.getCode());
|
||||
return updateTask(dynamicTaskUpdateRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean cancelTask(Long taskId) {
|
||||
DynamicTaskInfoResponse task = getTask(taskId);
|
||||
if (Objects.isNull(task)) {
|
||||
throw new BusinessException("task不存在!");
|
||||
}
|
||||
DynamicTaskUpdateRequest dynamicTaskUpdateRequest = buildUpdateTaskRequest(task);
|
||||
dynamicTaskUpdateRequest.setStatus(TaskStatusEnum.CANCELED.getCode());
|
||||
return updateTask(dynamicTaskUpdateRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean finishTask(Long taskId) {
|
||||
DynamicTaskInfoResponse task = getTask(taskId);
|
||||
if (Objects.isNull(task)) {
|
||||
throw new BusinessException("task不存在!");
|
||||
}
|
||||
DynamicTaskUpdateRequest dynamicTaskUpdateRequest = buildUpdateTaskRequest(task);
|
||||
dynamicTaskUpdateRequest.setStatus(TaskStatusEnum.FINISHED.getCode());
|
||||
return updateTask(dynamicTaskUpdateRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean errTask(Long taskId) {
|
||||
DynamicTaskInfoResponse task = getTask(taskId);
|
||||
if (Objects.isNull(task)) {
|
||||
throw new BusinessException("task不存在!");
|
||||
}
|
||||
DynamicTaskUpdateRequest dynamicTaskUpdateRequest = buildUpdateTaskRequest(task);
|
||||
dynamicTaskUpdateRequest.setStatus(TaskStatusEnum.ERROR.getCode());
|
||||
return updateTask(dynamicTaskUpdateRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DynamicTaskInfoResponse> getTaskList(DynamicTaskQueryRequest entity) {
|
||||
return ResultUtils.getData(dynamicTaskApi.list(entity));
|
||||
}
|
||||
|
||||
private DynamicTaskUpdateRequest buildUpdateTaskRequest(DynamicTaskInfoResponse response) {
|
||||
DynamicTaskUpdateRequest dynamicTaskUpdateRequest = new DynamicTaskUpdateRequest();
|
||||
dynamicTaskUpdateRequest.setId(response.getId());
|
||||
dynamicTaskUpdateRequest.setTaskName(response.getTaskName());
|
||||
dynamicTaskUpdateRequest.setTaskGroup(response.getTaskGroup());
|
||||
dynamicTaskUpdateRequest.setRunTime(response.getRunTime());
|
||||
dynamicTaskUpdateRequest.setStatus(response.getStatus());
|
||||
dynamicTaskUpdateRequest.setParameters(response.getParameters());
|
||||
return dynamicTaskUpdateRequest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.xiang.core.schedule.service;
|
||||
|
||||
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskQueryRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskSaveRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.request.DynamicTaskUpdateRequest;
|
||||
import com.xiang.quartz.common.entity.dynamic.response.DynamicTaskInfoResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public interface IDynamicTaskSchedulerService {
|
||||
Boolean saveTask(DynamicTaskSaveRequest entity);
|
||||
Boolean updateTask(DynamicTaskUpdateRequest entity);
|
||||
DynamicTaskInfoResponse getTask(Long taskId);
|
||||
Boolean updateProcess(Long taskId);
|
||||
Boolean cancelTask(Long taskId);
|
||||
Boolean finishTask(Long taskId);
|
||||
Boolean errTask(Long taskId);
|
||||
List<DynamicTaskInfoResponse> getTaskList(DynamicTaskQueryRequest entity);
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.xiang.core.quartz.config.XxzJobAutoConfiguration
|
||||
com.xiang.core.quartz.config.XxzJobAutoConfiguration, \
|
||||
com.xiang.core.schedule.config.DynamicSchedulerAutoConfiguration
|
||||
Reference in New Issue
Block a user