feat: 使用liteflow替换自定义的任务执行
This commit is contained in:
@@ -9,107 +9,116 @@
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>leopard-server</artifactId>
|
||||
<artifactId>leopard-server</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.lanyuanxiaoyao</groupId>
|
||||
<artifactId>spring-boot-service-template</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jetty</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.lanyuanxiaoyao</groupId>
|
||||
<artifactId>spring-boot-service-template</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jetty</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>liteflow-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-jpamodelgen</artifactId>
|
||||
<version>6.6.8.Final</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>io.github.openfeign.querydsl</groupId>
|
||||
<artifactId>querydsl-apt</artifactId>
|
||||
<version>7.0</version>
|
||||
<classifier>jpa</classifier>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>jakarta.persistence</groupId>
|
||||
<artifactId>jakarta.persistence-api</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-jpamodelgen</artifactId>
|
||||
<version>6.6.8.Final</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>io.github.openfeign.querydsl</groupId>
|
||||
<artifactId>querydsl-apt</artifactId>
|
||||
<version>7.0</version>
|
||||
<classifier>jpa</classifier>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>jakarta.persistence</groupId>
|
||||
<artifactId>jakarta.persistence-api</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -2,14 +2,15 @@ package com.lanyuanxiaoyao.leopard.server.controller;
|
||||
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.Stock;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.Task;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.StockService;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.TaskTemplateService;
|
||||
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.Trigger;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -82,9 +83,11 @@ public class CommonOptionsController {
|
||||
);
|
||||
|
||||
private final StockService stockService;
|
||||
private final TaskTemplateService taskTemplateService;
|
||||
|
||||
public CommonOptionsController(StockService stockService) {
|
||||
public CommonOptionsController(StockService stockService, TaskTemplateService taskTemplateService) {
|
||||
this.stockService = stockService;
|
||||
this.taskTemplateService = taskTemplateService;
|
||||
}
|
||||
|
||||
@GetMapping("/options/{name}")
|
||||
@@ -107,9 +110,10 @@ public class CommonOptionsController {
|
||||
new Option("已退市", false)
|
||||
)
|
||||
);
|
||||
case "task_template_type" -> GlobalResponse.responseSuccess(
|
||||
Arrays.stream(TaskTemplate.Type.values())
|
||||
.map(type -> new Option(type.getChineseName(), type.name()))
|
||||
case "task_template_id" -> GlobalResponse.responseSuccess(
|
||||
taskTemplateService.list()
|
||||
.stream()
|
||||
.map(template -> new Option(template.getName(), template.getId()))
|
||||
.toList()
|
||||
);
|
||||
default -> GlobalResponse.responseSuccess(List.of());
|
||||
@@ -138,10 +142,15 @@ public class CommonOptionsController {
|
||||
.toList(),
|
||||
field
|
||||
));
|
||||
case "task_template_type" -> GlobalResponse.responseSuccess(buildMapping(
|
||||
Arrays.stream(TaskTemplate.Type.values())
|
||||
.map(type -> new Mapping(type.name(), type.getChineseName()))
|
||||
.toList(),
|
||||
case "trigger_status" -> GlobalResponse.responseSuccess(buildMapping(
|
||||
List.of(
|
||||
new Mapping(Trigger.TriggerState.NONE.name(), "无"),
|
||||
new Mapping(Trigger.TriggerState.NORMAL.name(), "正常"),
|
||||
new Mapping(Trigger.TriggerState.PAUSED.name(), "暂停"),
|
||||
new Mapping(Trigger.TriggerState.COMPLETE.name(), "完成"),
|
||||
new Mapping(Trigger.TriggerState.ERROR.name(), "错误"),
|
||||
new Mapping(Trigger.TriggerState.BLOCKED.name(), "阻塞")
|
||||
),
|
||||
field
|
||||
));
|
||||
default -> GlobalResponse.responseSuccess(Map.of());
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.lanyuanxiaoyao.leopard.server.controller;
|
||||
|
||||
import com.lanyuanxiaoyao.leopard.server.service.QuartzService;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.TaskTemplateService;
|
||||
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.Trigger;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
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;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("task_schedule")
|
||||
public class QuartzController {
|
||||
private final QuartzService quartzService;
|
||||
private final TaskTemplateService taskTemplateService;
|
||||
|
||||
public QuartzController(QuartzService quartzService, TaskTemplateService taskTemplateService) {
|
||||
this.quartzService = quartzService;
|
||||
this.taskTemplateService = taskTemplateService;
|
||||
}
|
||||
|
||||
@PostMapping("save")
|
||||
public GlobalResponse<Object> save(@RequestBody SaveItem item) throws SchedulerException {
|
||||
quartzService.save(item.templateId(), item.cron());
|
||||
return GlobalResponse.responseSuccess();
|
||||
}
|
||||
|
||||
@GetMapping("list")
|
||||
public GlobalResponse<List<ListItem>> list() throws SchedulerException {
|
||||
var list = quartzService.list()
|
||||
.stream()
|
||||
.map(task -> {
|
||||
var template = taskTemplateService.detail(task.templateId());
|
||||
return new ListItem(
|
||||
task.key(),
|
||||
template.getName(),
|
||||
template.getDescription(),
|
||||
task.cron(),
|
||||
task.status(),
|
||||
task.previousFireTime(),
|
||||
task.nextFireTime()
|
||||
);
|
||||
})
|
||||
.toList();
|
||||
return GlobalResponse.responseSuccess(list);
|
||||
}
|
||||
|
||||
@GetMapping("pause/{key}")
|
||||
public GlobalResponse<Object> pause(@PathVariable("key") String key) throws SchedulerException {
|
||||
quartzService.pause(key);
|
||||
return GlobalResponse.responseSuccess();
|
||||
}
|
||||
|
||||
@GetMapping("resume/{key}")
|
||||
public GlobalResponse<Object> resume(@PathVariable("key") String key) throws SchedulerException {
|
||||
quartzService.resume(key);
|
||||
return GlobalResponse.responseSuccess();
|
||||
}
|
||||
|
||||
@GetMapping("remove/{key}")
|
||||
public GlobalResponse<Object> remove(@PathVariable("key") String key) throws SchedulerException {
|
||||
quartzService.remove(key);
|
||||
return GlobalResponse.responseSuccess();
|
||||
}
|
||||
|
||||
public record SaveItem(
|
||||
Long templateId,
|
||||
String cron
|
||||
) {
|
||||
}
|
||||
|
||||
public record ListItem(
|
||||
String key,
|
||||
String templateName,
|
||||
String templateDescription,
|
||||
String cron,
|
||||
Trigger.TriggerState status,
|
||||
LocalDateTime previousFireTime,
|
||||
LocalDateTime nextFireTime
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.lanyuanxiaoyao.leopard.server.service.TaskService;
|
||||
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
|
||||
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -36,7 +37,7 @@ public class TaskController extends SimpleControllerSupport<Task, Void, TaskCont
|
||||
|
||||
@PostMapping("execute")
|
||||
public GlobalResponse<Object> execute(@RequestBody ExecuteRequest request) {
|
||||
taskService.execute(request.templateId());
|
||||
taskService.execute(request.templateId(), request.params());
|
||||
return GlobalResponse.responseSuccess();
|
||||
}
|
||||
|
||||
@@ -93,6 +94,6 @@ public class TaskController extends SimpleControllerSupport<Task, Void, TaskCont
|
||||
) {
|
||||
}
|
||||
|
||||
public record ExecuteRequest(Long templateId) {
|
||||
public record ExecuteRequest(Long templateId, Map<String, Object> params) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.lanyuanxiaoyao.leopard.server.controller;
|
||||
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.templates.ClassTaskTemplate;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.TaskTemplateService;
|
||||
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
|
||||
import java.util.function.Function;
|
||||
@@ -20,26 +19,22 @@ public class TaskTemplateController extends SimpleControllerSupport<TaskTemplate
|
||||
@Override
|
||||
protected Function<Item, TaskTemplate> saveItemMapper() {
|
||||
return item -> {
|
||||
return switch (item.type) {
|
||||
case CLASS -> {
|
||||
var template = new ClassTaskTemplate();
|
||||
template.setId(item.id());
|
||||
template.setName(item.name());
|
||||
template.setDescription(item.description());
|
||||
template.setClazz(item.clazz());
|
||||
yield template;
|
||||
}
|
||||
};
|
||||
var template = new TaskTemplate();
|
||||
template.setId(item.id());
|
||||
template.setName(item.name());
|
||||
template.setDescription(item.description());
|
||||
template.setChain(item.chain());
|
||||
return template;
|
||||
};
|
||||
}
|
||||
|
||||
private Item convert(TaskTemplate template) {
|
||||
return switch (template.getType()) {
|
||||
case CLASS -> {
|
||||
ClassTaskTemplate classTaskTemplate = (ClassTaskTemplate) template;
|
||||
yield new Item(classTaskTemplate.getId(), classTaskTemplate.getName(), classTaskTemplate.getDescription(), classTaskTemplate.getType(), classTaskTemplate.getClazz());
|
||||
}
|
||||
};
|
||||
return new Item(
|
||||
template.getId(),
|
||||
template.getName(),
|
||||
template.getDescription(),
|
||||
template.getChain()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,8 +51,7 @@ public class TaskTemplateController extends SimpleControllerSupport<TaskTemplate
|
||||
Long id,
|
||||
String name,
|
||||
String description,
|
||||
TaskTemplate.Type type,
|
||||
String clazz
|
||||
String chain
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package com.lanyuanxiaoyao.leopard.server.entity;
|
||||
|
||||
import com.lanyuanxiaoyao.leopard.server.Constants;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.base.SimpleEnum;
|
||||
import com.lanyuanxiaoyao.service.template.entity.SimpleEntity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.Inheritance;
|
||||
import jakarta.persistence.InheritanceType;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
@@ -29,20 +25,11 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
@DynamicInsert
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@Table(name = Constants.DATABASE_PREFIX + "task_template")
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
public abstract class TaskTemplate extends SimpleEntity {
|
||||
public class TaskTemplate extends SimpleEntity {
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
@Column(nullable = false, length = 500)
|
||||
private String description;
|
||||
|
||||
public abstract Type getType();
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum Type implements SimpleEnum {
|
||||
CLASS("类任务");
|
||||
|
||||
private final String chineseName;
|
||||
}
|
||||
@Column(nullable = false)
|
||||
private String chain;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.lanyuanxiaoyao.leopard.server.entity.templates;
|
||||
|
||||
import com.lanyuanxiaoyao.leopard.server.Constants;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityListeners;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.hibernate.annotations.SoftDelete;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@ToString(callSuper = true)
|
||||
@FieldNameConstants
|
||||
@Entity
|
||||
@SoftDelete
|
||||
@DynamicUpdate
|
||||
@DynamicInsert
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@Table(name = Constants.DATABASE_PREFIX + "task_template_class")
|
||||
public class ClassTaskTemplate extends TaskTemplate {
|
||||
@Column(nullable = false)
|
||||
private String clazz;
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.CLASS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.lanyuanxiaoyao.leopard.server.service;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.CronScheduleBuilder;
|
||||
import org.quartz.CronTrigger;
|
||||
import org.quartz.JobBuilder;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.Trigger;
|
||||
import org.quartz.TriggerBuilder;
|
||||
import org.quartz.impl.matchers.GroupMatcher;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class QuartzService {
|
||||
private final Scheduler scheduler;
|
||||
|
||||
public QuartzService(Scheduler scheduler) {
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
public List<QuartzTask> list() throws SchedulerException {
|
||||
var tasks = new ArrayList<QuartzTask>();
|
||||
for (var key : scheduler.getJobKeys(GroupMatcher.anyGroup())) {
|
||||
var detail = scheduler.getJobDetail(key);
|
||||
var trigger = (CronTrigger) scheduler.getTriggersOfJob(key).get(0);
|
||||
tasks.add(new QuartzTask(
|
||||
detail.getKey().getName(),
|
||||
detail.getJobDataMap().getLong("template_id"),
|
||||
trigger.getCronExpression(),
|
||||
scheduler.getTriggerState(trigger.getKey()),
|
||||
ObjectUtil.isNull(trigger.getPreviousFireTime()) ? null : LocalDateTime.ofInstant(trigger.getPreviousFireTime().toInstant(), ZoneId.systemDefault()),
|
||||
ObjectUtil.isNull(trigger.getNextFireTime()) ? null : LocalDateTime.ofInstant(trigger.getNextFireTime().toInstant(), ZoneId.systemDefault())
|
||||
));
|
||||
}
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public void save(Long templateId, String cron) throws SchedulerException {
|
||||
var detail = JobBuilder.newJob(TaskExecutionJob.class)
|
||||
.withIdentity("task_execution_" + IdUtil.fastUUID())
|
||||
.usingJobData("template_id", templateId)
|
||||
.storeDurably()
|
||||
.build();
|
||||
var trigger = TriggerBuilder.newTrigger()
|
||||
.forJob(detail)
|
||||
.withIdentity("task_execution_" + IdUtil.fastUUID())
|
||||
.withSchedule(
|
||||
CronScheduleBuilder.cronSchedule(cron)
|
||||
.withMisfireHandlingInstructionDoNothing()
|
||||
)
|
||||
.build();
|
||||
scheduler.scheduleJob(detail, trigger);
|
||||
}
|
||||
|
||||
public void pause(String jobKey) throws SchedulerException {
|
||||
scheduler.pauseJob(JobKey.jobKey(jobKey));
|
||||
}
|
||||
|
||||
public void resume(String jobKey) throws SchedulerException {
|
||||
scheduler.resumeJob(JobKey.jobKey(jobKey));
|
||||
}
|
||||
|
||||
public void remove(String jobKey) throws SchedulerException {
|
||||
pause(jobKey);
|
||||
scheduler.deleteJob(JobKey.jobKey(jobKey));
|
||||
}
|
||||
|
||||
@Slf4j
|
||||
public static class TaskExecutionJob extends QuartzJobBean {
|
||||
private final TaskService taskService;
|
||||
|
||||
public TaskExecutionJob(TaskService taskService) {
|
||||
this.taskService = taskService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext context) {
|
||||
var dataMap = context.getMergedJobDataMap();
|
||||
var templateId = dataMap.getLong("template_id");
|
||||
var parms = (Map<String, Object>) dataMap.getOrDefault("params", Map.of());
|
||||
taskService.execute(templateId, parms);
|
||||
}
|
||||
}
|
||||
|
||||
public record QuartzTask(
|
||||
String key,
|
||||
Long templateId,
|
||||
String cron,
|
||||
Trigger.TriggerState status,
|
||||
LocalDateTime previousFireTime,
|
||||
LocalDateTime nextFireTime
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
package com.lanyuanxiaoyao.leopard.server.service;
|
||||
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.Task;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.templates.ClassTaskTemplate;
|
||||
import com.lanyuanxiaoyao.leopard.server.repository.TaskRepository;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.task.TaskRunner;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.task.TaskMonitorNodes;
|
||||
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@@ -19,26 +16,18 @@ import org.springframework.stereotype.Service;
|
||||
@Slf4j
|
||||
@Service
|
||||
public class TaskService extends SimpleServiceSupport<Task> {
|
||||
private final ApplicationContext context;
|
||||
private final TaskTemplateService taskTemplateService;
|
||||
private final ExecutorService executors = Executors.newFixedThreadPool(50);
|
||||
private final FlowExecutor flowExecutor;
|
||||
|
||||
public TaskService(TaskRepository repository, ApplicationContext context, TaskTemplateService taskTemplateService) {
|
||||
public TaskService(TaskRepository repository, TaskTemplateService taskTemplateService, @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") FlowExecutor flowExecutor) {
|
||||
super(repository);
|
||||
this.context = context;
|
||||
this.taskTemplateService = taskTemplateService;
|
||||
this.flowExecutor = flowExecutor;
|
||||
}
|
||||
|
||||
public void execute(Long templateId) {
|
||||
public void execute(Long templateId, Map<String, Object> params) {
|
||||
var template = taskTemplateService.detail(templateId);
|
||||
switch (template.getType()) {
|
||||
case CLASS -> {
|
||||
ClassTaskTemplate classTaskTemplate = (ClassTaskTemplate) template;
|
||||
var runner = context.getBean(classTaskTemplate.getClazz(), TaskRunner.class);
|
||||
executors.submit(() -> {
|
||||
runner.runTask(classTaskTemplate, Map.of());
|
||||
});
|
||||
}
|
||||
}
|
||||
var context = new TaskMonitorNodes.TaskMonitorContext(template);
|
||||
flowExecutor.execute2Future(template.getChain(), params, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.lanyuanxiaoyao.leopard.server.service.task;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.Task;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowFact;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@LiteflowComponent
|
||||
public class TaskMonitorNodes {
|
||||
private final TaskService taskService;
|
||||
|
||||
public TaskMonitorNodes(TaskService taskService) {
|
||||
this.taskService = taskService;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "task_start", nodeName = "任务开始", nodeType = NodeTypeEnum.COMMON)
|
||||
public void taskStart(NodeComponent node) {
|
||||
var context = node.getContextBean(TaskMonitorContext.class);
|
||||
if (ObjectUtil.isNotNull(context)) {
|
||||
var task = new Task();
|
||||
task.setName(context.getTemplate().getName());
|
||||
task.setDescription(context.getTemplate().getDescription());
|
||||
task.setStatus(Task.Status.RUNNING);
|
||||
task.setLaunchedTime(LocalDateTime.now());
|
||||
var taskId = taskService.save(task);
|
||||
context.setTaskId(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "task_end", nodeName = "任务结束", nodeType = NodeTypeEnum.COMMON)
|
||||
public void taskEnd(NodeComponent node, @LiteflowFact("taskId") Long taskId) {
|
||||
if (ObjectUtil.isNotNull(taskId)) {
|
||||
var task = taskService.detail(taskId);
|
||||
task.setStatus(Task.Status.SUCCESS);
|
||||
task.setFinishedTime(LocalDateTime.now());
|
||||
var result = node.<String>getContextValue("taskResult");
|
||||
if (StrUtil.isNotBlank(result)) {
|
||||
task.setResult(result);
|
||||
}
|
||||
taskService.save(task);
|
||||
}
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "task_error", nodeName = "任务错误", nodeType = NodeTypeEnum.COMMON)
|
||||
public void taskError(NodeComponent node, @LiteflowFact("taskId") Long taskId) {
|
||||
if (ObjectUtil.isNotNull(taskId)) {
|
||||
var task = taskService.detail(taskId);
|
||||
task.setStatus(Task.Status.FAILURE);
|
||||
task.setFinishedTime(LocalDateTime.now());
|
||||
var exception = node.getSlot().getException();
|
||||
if (ObjectUtil.isNotNull(exception)) {
|
||||
task.setError(exception.getMessage());
|
||||
}
|
||||
taskService.save(task);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static final class TaskMonitorContext {
|
||||
private TaskTemplate template;
|
||||
private Long taskId;
|
||||
private String taskResult;
|
||||
|
||||
public TaskMonitorContext(TaskTemplate template) {
|
||||
this.template = template;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.lanyuanxiaoyao.leopard.server.service.task;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.Task;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.TaskTemplate;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public abstract class TaskRunner {
|
||||
private final TaskService taskService;
|
||||
|
||||
protected TaskRunner(TaskService taskService) {
|
||||
this.taskService = taskService;
|
||||
}
|
||||
|
||||
public void runTask(TaskTemplate template, Map<String, Object> params) {
|
||||
var task = new Task();
|
||||
task.setName(template.getName());
|
||||
task.setDescription(template.getDescription());
|
||||
task.setStatus(Task.Status.RUNNING);
|
||||
task.setLaunchedTime(LocalDateTime.now());
|
||||
task.setId(taskService.save(task));
|
||||
try {
|
||||
var result = run(params);
|
||||
task.setStatus(Task.Status.SUCCESS);
|
||||
if (StrUtil.isNotBlank(result)) {
|
||||
task.setResult(result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
task.setStatus(Task.Status.FAILURE);
|
||||
task.setError(e.getMessage());
|
||||
}
|
||||
task.setFinishedTime(LocalDateTime.now());
|
||||
taskService.save(task);
|
||||
}
|
||||
|
||||
abstract String run(Map<String, Object> params);
|
||||
}
|
||||
@@ -4,25 +4,25 @@ import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.lanyuanxiaoyao.leopard.server.entity.Stock;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.StockService;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
|
||||
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
|
||||
import java.util.Map;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import jakarta.transaction.Transactional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("com.lanyuanxiaoyao.leopard.server.service.task.UpdateStockInformationTask")
|
||||
public class UpdateStockInformationTask extends TaskRunner {
|
||||
@LiteflowComponent("update_stock_information")
|
||||
public class UpdateStockInformationNode extends NodeComponent {
|
||||
private final StockService stockService;
|
||||
private final TuShareService tuShareService;
|
||||
|
||||
public UpdateStockInformationTask(TaskService taskService, StockService stockService, TuShareService tuShareService) {
|
||||
super(taskService);
|
||||
public UpdateStockInformationNode(StockService stockService, TuShareService tuShareService) {
|
||||
this.stockService = stockService;
|
||||
this.tuShareService = tuShareService;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = Throwable.class)
|
||||
@Override
|
||||
public String run(Map<String, Object> params) {
|
||||
public void process() throws Exception {
|
||||
var stocks = stockService.list();
|
||||
var stocksMap = stocks.stream().collect(Collectors.toMap(Stock::getCode, stock -> stock));
|
||||
tuShareService.stockList()
|
||||
@@ -54,6 +54,5 @@ public class UpdateStockInformationTask extends TaskRunner {
|
||||
}
|
||||
});
|
||||
stockService.save(stocks);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -15,5 +15,15 @@ spring:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jpa:
|
||||
generate-ddl: true
|
||||
quartz:
|
||||
wait-for-jobs-to-complete-on-shutdown: true
|
||||
startup-delay: 30s
|
||||
job-store-type: jdbc
|
||||
jdbc:
|
||||
platform: mysql
|
||||
fenix:
|
||||
print-banner: false
|
||||
liteflow:
|
||||
print-banner: false
|
||||
rule-source: flow.xml
|
||||
check-node-exists: false
|
||||
7
leopard-server/src/main/resources/flow.xml
Normal file
7
leopard-server/src/main/resources/flow.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE flow PUBLIC "liteflow" "https://liteflow.cc/liteflow.dtd">
|
||||
<flow>
|
||||
<chain id="update_stock_information">
|
||||
CATCH(THEN(task_start, update_stock_information, task_end)).DO(task_error)
|
||||
</chain>
|
||||
</flow>
|
||||
Reference in New Issue
Block a user