refactor: 优化项目模块命名(简化、分类、统一)

This commit is contained in:
2024-10-30 23:01:54 +08:00
parent 9ecdeb52f6
commit c276e53a8e
346 changed files with 160 additions and 162 deletions

View File

@@ -0,0 +1,39 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>top.continew</groupId>
<artifactId>continew-plugin</artifactId>
<version>${revision}</version>
</parent>
<artifactId>continew-plugin-schedule</artifactId>
<description>任务调度插件</description>
<dependencies>
<!-- SnailJob灵活可靠和快速的分布式任务重试和分布式任务调度平台 -->
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-starter</artifactId>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-retry-core</artifactId>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-job-core</artifactId>
</dependency>
<!-- Spring WebFlux异步非阻塞 Web 框架) -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-http</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.api;
import com.aizuda.snailjob.common.core.model.Result;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.service.annotation.*;
import top.continew.admin.schedule.model.JobPageResult;
import top.continew.admin.schedule.model.req.JobReq;
import top.continew.admin.schedule.model.req.JobStatusReq;
import top.continew.admin.schedule.model.resp.JobResp;
import java.util.List;
import java.util.Set;
/**
* 任务 REST API
*
* @author KAI
* @author Charles7c
* @since 2024/6/25 18:20
*/
@HttpExchange(accept = MediaType.APPLICATION_JSON_VALUE)
public interface JobApi {
/**
* 分页查询列表
*
* @param groupName 任务组
* @param jobName 任务名称
* @param jobStatus 任务状态
* @param page 页码
* @param size 每页条数
* @return 响应信息
*/
@GetExchange("/job/page/list")
ResponseEntity<JobPageResult<List<JobResp>>> page(@RequestParam(value = "groupName", required = false) String groupName,
@RequestParam(value = "jobName", required = false) String jobName,
@RequestParam(value = "jobStatus", required = false) Integer jobStatus,
@RequestParam("page") int page,
@RequestParam("size") int size);
/**
* 新增
*
* @param req 新增信息
* @return 响应信息
*/
@PostExchange("/job")
ResponseEntity<Result<Boolean>> add(@RequestBody JobReq req);
/**
* 修改
*
* @param req 修改信息
* @return 响应信息
*/
@PutExchange("/job")
ResponseEntity<Result<Boolean>> update(@RequestBody JobReq req);
/**
* 修改状态
*
* @param req 修改信息
* @return 响应信息
*/
@PutExchange("/job/status")
ResponseEntity<Result<Boolean>> updateStatus(@RequestBody JobStatusReq req);
/**
* 删除
*
* @param ids ID 列表
* @return 响应信息
*/
@DeleteExchange("/job/ids")
ResponseEntity<Result<Boolean>> delete(@RequestBody Set<Long> ids);
/**
* 执行
*
* @param id ID
* @return 响应信息
*/
@PostExchange("/job/trigger/{id}")
ResponseEntity<Result<Boolean>> trigger(@PathVariable("id") Long id);
/**
* 查询分组列表
*
* @return 响应信息
*/
@GetExchange("/group/all/group-name/list")
ResponseEntity<Result<List<String>>> listGroup();
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.api;
import com.aizuda.snailjob.common.core.model.Result;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.HttpExchange;
import org.springframework.web.service.annotation.PostExchange;
import top.continew.admin.schedule.model.JobInstanceLogPageResult;
import top.continew.admin.schedule.model.JobPageResult;
import top.continew.admin.schedule.model.resp.JobInstanceResp;
import top.continew.admin.schedule.model.resp.JobLogResp;
import java.util.List;
/**
* 任务批次 REST API
*
* @author KAI
* @author Charles7c
* @since 2024/6/27 23:03
*/
@HttpExchange(value = "/job", accept = MediaType.APPLICATION_JSON_VALUE)
public interface JobBatchApi {
/**
* 分页查询列表
*
* @param jobId 任务 ID
* @param jobName 任务名称
* @param groupName 组名称
* @param taskBatchStatus 任务批次状态
* @param datetimeRange 时间范围
* @param page 页码
* @param size 每页条数
* @return 响应信息
*/
@GetExchange("/batch/list")
ResponseEntity<JobPageResult<List<JobLogResp>>> page(@RequestParam(value = "jobId", required = false) Long jobId,
@RequestParam(value = "jobName", required = false) String jobName,
@RequestParam(value = "groupName", required = false) String groupName,
@RequestParam(value = "taskBatchStatus", required = false) Integer taskBatchStatus,
@RequestParam(value = "datetimeRange", required = false) String[] datetimeRange,
@RequestParam(value = "page") Integer page,
@RequestParam(value = "size") Integer size);
/**
* 停止
*
* @param id ID
* @return 响应信息
*/
@PostExchange("/batch/stop/{id}")
ResponseEntity<Result<Boolean>> stop(@PathVariable("id") Long id);
/**
* 重试
*
* @param id ID
* @return 响应信息
*/
@PostExchange("/batch/retry/{id}")
ResponseEntity<Result<Boolean>> retry(@PathVariable("id") Long id);
/**
* 分页查询任务实例列表
*
* @param jobId 任务 ID
* @param taskBatchId 任务批次 ID
* @param page 页码
* @param size 每页条数
* @return 响应信息
*/
@GetExchange("/task/list")
ResponseEntity<JobPageResult<List<JobInstanceResp>>> pageTask(@RequestParam(value = "jobId", required = false) Long jobId,
@RequestParam(value = "taskBatchId") Long taskBatchId,
@RequestParam(value = "page") Integer page,
@RequestParam(value = "size") Integer size);
/**
* 分页查询任务实例日志列表
*
* @param jobId 任务 ID
* @param taskBatchId 任务批次 ID
* @param taskId 任务实例ID
* @param startId 起始 ID
* @param fromIndex 起始索引
* @param size 每页条数
* @return 响应信息
*/
@GetExchange("/log/list")
ResponseEntity<Result<JobInstanceLogPageResult>> pageLog(@RequestParam(value = "jobId", required = false) Long jobId,
@RequestParam(value = "taskBatchId") Long taskBatchId,
@RequestParam(value = "taskId") Long taskId,
@RequestParam(value = "startId") Integer startId,
@RequestParam(value = "fromIndex") Integer fromIndex,
@RequestParam(value = "size") Integer size);
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.api;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.RegisteredPayload;
import com.aizuda.snailjob.common.core.model.Result;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import top.continew.admin.schedule.constant.JobConstants;
import top.continew.admin.schedule.model.JobPageResult;
import top.continew.starter.cache.redisson.util.RedisUtils;
import top.continew.starter.extension.crud.model.resp.PageResp;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
/**
* 任务调度客户端
*
* @author Charles7c
* @since 2024/7/4 23:07
*/
@Slf4j
@Data
public class JobClient {
public static final Integer STATUS_SUCCESS = 1;
private static final String AUTH_URL = "/auth/login";
private final String url;
private final String username;
private final String password;
public JobClient(String url, String username, String password) {
Assert.notBlank(url, "任务调度中心 URL 不能为空");
Assert.notBlank(username, "任务调度中心用户名不能为空");
Assert.notBlank(password, "任务调度中心密码不能为空");
this.url = url;
this.username = username;
this.password = password;
}
/**
* 请求
*
* @param apiSupplier API 请求
* @param <T> 响应类型
* @return 响应信息
*/
public <T> T request(Supplier<ResponseEntity<Result<T>>> apiSupplier) {
ResponseEntity<Result<T>> responseEntity = apiSupplier.get();
this.checkResponse(responseEntity);
Result<T> result = responseEntity.getBody();
if (!STATUS_SUCCESS.equals(result.getStatus())) {
throw new IllegalStateException(result.getMessage());
}
return result.getData();
}
/**
* 分页请求
*
* @param apiSupplier API 请求
* @param <T> 响应类型
* @return 分页列表信息
*/
public <T> PageResp<T> requestPage(Supplier<ResponseEntity<JobPageResult<List<T>>>> apiSupplier) {
ResponseEntity<JobPageResult<List<T>>> responseEntity = apiSupplier.get();
this.checkResponse(responseEntity);
JobPageResult<List<T>> result = responseEntity.getBody();
if (!STATUS_SUCCESS.equals(result.getStatus())) {
throw new IllegalStateException(result.getMessage());
}
PageResp<T> page = new PageResp<>();
page.setList(result.getData());
page.setTotal(result.getTotal());
return page;
}
/**
* 获取 Token
*
* @return Token
*/
public String getToken() {
String token = RedisUtils.get(JobConstants.AUTH_TOKEN_HEADER);
if (StrUtil.isBlank(token)) {
token = this.authenticate();
Object expiresAtSeconds = JWTUtil.parseToken(token).getPayload(RegisteredPayload.EXPIRES_AT);
RedisUtils.set(JobConstants.AUTH_TOKEN_HEADER, token, Duration.ofSeconds(Convert
.toLong(expiresAtSeconds) - DateUtil.currentSeconds() - 60));
}
return token;
}
/**
* 密码认证
*
* @return Token
*/
private String authenticate() {
Map<String, Object> paramMap = MapUtil.newHashMap(2);
paramMap.put("username", username);
paramMap.put("password", SecureUtil.md5(password));
HttpRequest httpRequest = HttpUtil.createPost("%s%s".formatted(url, AUTH_URL));
httpRequest.body(JSONUtil.toJsonStr(paramMap));
HttpResponse response = httpRequest.execute();
if (!response.isOk() || response.body() == null) {
throw new IllegalStateException("连接任务调度中心异常");
}
Result<?> result = JSONUtil.toBean(response.body(), Result.class);
if (!STATUS_SUCCESS.equals(result.getStatus())) {
log.warn("Password Authentication failed, expected a successful response. error msg: {}", result
.getMessage());
throw new IllegalStateException(result.getMessage());
}
return JSONUtil.parseObj(result.getData()).getStr("token");
}
/**
* 检查响应
*
* @param responseEntity 响应信息
*/
private void checkResponse(ResponseEntity<?> responseEntity) {
if (!responseEntity.getStatusCode().is2xxSuccessful() || responseEntity.getBody() == null) {
throw new IllegalStateException("连接任务调度中心异常");
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.support.WebClientAdapter;
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import top.continew.admin.schedule.api.JobApi;
import top.continew.admin.schedule.api.JobBatchApi;
import top.continew.admin.schedule.api.JobClient;
import top.continew.admin.schedule.constant.JobConstants;
/**
* HTTP Exchange 配置
*
* @author KAI
* @author Charles7c
* @since 2024/6/25 18:03
*/
@Slf4j
@Configuration
@RequiredArgsConstructor
public class HttpExchangeConfiguration {
private final ObjectMapper objectMapper;
@Value("${snail-job.namespace}")
private String namespace;
@Value("${snail-job.server.api.url}")
private String baseUrl;
@Value("${snail-job.server.api.username}")
private String username;
@Value("${snail-job.server.api.password}")
private String password;
@Bean
public JobApi jobApi() {
return httpServiceProxyFactory().createClient(JobApi.class);
}
@Bean
public JobBatchApi jobBatchApi() {
return httpServiceProxyFactory().createClient(JobBatchApi.class);
}
@Bean
public HttpServiceProxyFactory httpServiceProxyFactory() {
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
.doOnConnected(conn -> {
conn.addHandlerLast(new ReadTimeoutHandler(10));
conn.addHandlerLast(new WriteTimeoutHandler(10));
})
.wiretap(true);
WebClient webClient = WebClient.builder()
.codecs(config -> config.defaultCodecs().jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper)))
.codecs(config -> config.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper)))
.clientConnector(new ReactorClientHttpConnector(httpClient))
.filter(logRequest())
.filter(logResponse())
.filter((request, next) -> {
// 设置请求头
ClientRequest filtered = ClientRequest.from(request)
.header(JobConstants.NAMESPACE_ID_HEADER, namespace)
.header(JobConstants.AUTH_TOKEN_HEADER, jobClient().getToken())
.build();
return next.exchange(filtered);
})
.baseUrl(baseUrl)
.build();
return HttpServiceProxyFactory.builderFor(WebClientAdapter.create(webClient)).build();
}
@Bean
public JobClient jobClient() {
return new JobClient(baseUrl, username, password);
}
/**
* 打印请求日志
*/
private ExchangeFilterFunction logRequest() {
return ExchangeFilterFunction.ofRequestProcessor(request -> {
log.info("---> {} {}", request.method(), request.url());
return Mono.just(request);
});
}
/**
* 打印响应日志
*/
private ExchangeFilterFunction logResponse() {
return ExchangeFilterFunction.ofResponseProcessor(response -> response.bodyToMono(String.class)
.flatMap(body -> {
log.info("<--- {}", response.statusCode());
log.info(body);
return Mono.just(ClientResponse.from(response).body(body).build());
}));
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.config;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import com.aizuda.snailjob.client.common.appender.SnailLogbackAppender;
import com.aizuda.snailjob.client.common.event.SnailClientStartingEvent;
import com.aizuda.snailjob.client.starter.EnableSnailJob;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
/**
* Snail Job 配置
*
* @author KAI
* @since 2024/6/26 9:19
*/
@Configuration
@EnableSnailJob
@ConditionalOnProperty(prefix = "snail-job", value = "enabled", havingValue = "true", matchIfMissing = true)
public class SnailJobConfiguration {
/**
* 日志上报
*/
@EventListener(SnailClientStartingEvent.class)
public void onStarting() {
SnailLogbackAppender<ILoggingEvent> appender = new SnailLogbackAppender<>();
appender.start();
LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory();
Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.addAppender(appender);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.constant;
/**
* 任务调度常量
*
* @author KAI
* @since 2024/6/26 9:19
*/
public class JobConstants {
/**
* 请求头:命名空间 ID
*/
public static final String NAMESPACE_ID_HEADER = "SNAIL-JOB-NAMESPACE-ID";
/**
* 请求头:认证令牌
*/
public static final String AUTH_TOKEN_HEADER = "Snail-Job-Auth";
private JobConstants() {
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import top.continew.starter.core.enums.BaseEnum;
/**
* 任务阻塞策略枚举
*
* @author Charles7c
* @since 2024/7/11 22:28
*/
@Getter
@RequiredArgsConstructor
public enum JobBlockStrategyEnum implements BaseEnum<Integer> {
/**
* 丢弃
*/
DISCARD(1, "丢弃"),
/**
* 覆盖
*/
COVER(2, "覆盖"),
/**
* 并行
*/
PARALLEL(3, "并行"),;
private final Integer value;
private final String description;
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import top.continew.starter.core.enums.BaseEnum;
/**
* 任务执行原因枚举
*
* @author Charles7c
* @since 2024/7/11 22:28
*/
@Getter
@RequiredArgsConstructor
public enum JobExecuteReasonEnum implements BaseEnum<Integer> {
/**
* 无
*/
NONE(0, ""),
/**
* 任务执行超时
*/
TIME_OUT(1, "任务执行超时"),
/**
* 无客户端节点
*/
CLIENT_NOT_FOUND(2, "无客户端节点"),
/**
* 任务已关闭
*/
TASK_CLOSED(3, "任务已关闭"),
/**
* 任务丢弃
*/
TASK_DROPPED(4, "任务丢弃"),
/**
* 任务被覆盖
*/
TASK_COVERED(5, "任务被覆盖"),
/**
* 无可执行任务项
*/
TASK_NONE(6, "无可执行任务项"),
/**
* 任务执行期间发生非预期异常
*/
TASK_EXCEPTION(7, "任务执行期间发生非预期异常"),
/**
* 手动停止
*/
MANUAL_STOP(8, "手动停止"),
/**
* 条件节点执行异常
*/
NODE_EXCEPTION(9, "条件节点执行异常"),
/**
* 任务中断
*/
TASK_INTERRUPT(10, "任务中断"),
/**
* 回调节点执行异常
*/
CALLBACK_EXCEPTION(11, "回调节点执行异常"),
/**
* 无需处理
*/
NO_NEED_PROCESS(12, "无需处理"),
/**
* 节点关闭跳过执行
*/
NODE_SKIP(13, "节点关闭跳过执行"),
/**
* 判定未通过
*/
NOT_PASS(14, "判定未通过"),
/**
* 任务已完成
*/
TASK_FINISHED(15, "任务已完成"),
/**
* 任务状态
*/
TASK_RUNNING(16, "任务正在执行"),
/**
* 任务等待执行
*/
TASK_WAITING(17, "任务等待执行"),
/**
* 任务执行失败
*/
TASK_FAILED(18, "任务执行失败"),
/**
* 任务执行成功
*/
TASK_SUCCESS(19, "任务执行成功"),;
private final Integer value;
private final String description;
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import top.continew.admin.common.constant.UiConstants;
import top.continew.starter.core.enums.BaseEnum;
/**
* 任务执行状态枚举
*
* @author Charles7c
* @since 2024/7/11 22:28
*/
@Getter
@RequiredArgsConstructor
public enum JobExecuteStatusEnum implements BaseEnum<Integer> {
/**
* 待处理
*/
WAITING(1, "待处理", UiConstants.COLOR_PRIMARY),
/**
* 运行中
*/
RUNNING(2, "运行中", UiConstants.COLOR_WARNING),
/**
* 成功
*/
SUCCEEDED(3, "成功", UiConstants.COLOR_SUCCESS),
/**
* 已失败
*/
FAILED(4, "已失败", UiConstants.COLOR_ERROR),
/**
* 已停止
*/
STOPPED(5, "已停止", UiConstants.COLOR_ERROR),
/**
* 已取消
*/
CANCELED(6, "已取消", UiConstants.COLOR_DEFAULT),;
private final Integer value;
private final String description;
private final String color;
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import top.continew.starter.core.enums.BaseEnum;
/**
* 任务路由策略枚举
*
* @author Charles7c
* @since 2024/7/11 22:28
*/
@Getter
@RequiredArgsConstructor
public enum JobRouteStrategyEnum implements BaseEnum<Integer> {
/**
* 轮询
*/
POLLING(4, "轮询"),
/**
* 随机
*/
RANDOM(2, "随机"),
/**
* 一致性哈希
*/
HASH(1, "一致性哈希"),
/**
* LRU
*/
LRU(3, "LRU"),;
private final Integer value;
private final String description;
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import top.continew.admin.common.constant.UiConstants;
import top.continew.starter.core.enums.BaseEnum;
/**
* 任务状态枚举
*
* @author Charles7c
* @since 2024/7/11 22:28
*/
@Getter
@RequiredArgsConstructor
public enum JobStatusEnum implements BaseEnum<Integer> {
/**
* 禁用
*/
DISABLED(0, "禁用", UiConstants.COLOR_ERROR),
/**
* 启用
*/
ENABLED(1, "启用", UiConstants.COLOR_SUCCESS),;
private final Integer value;
private final String description;
private final String color;
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import top.continew.admin.common.constant.UiConstants;
import top.continew.starter.core.enums.BaseEnum;
/**
* 任务类型枚举
*
* @author Charles7c
* @since 2024/7/11 22:28
*/
@Getter
@RequiredArgsConstructor
public enum JobTaskTypeEnum implements BaseEnum<Integer> {
/**
* 集群
*/
CLUSTER(1, "集群", UiConstants.COLOR_PRIMARY),
/**
* 广播
*/
BROADCAST(2, "广播", UiConstants.COLOR_PRIMARY),
/**
* 静态切片
*/
SLICE(3, "静态切片", UiConstants.COLOR_PRIMARY),;
private final Integer value;
private final String description;
private final String color;
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.enums;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import top.continew.starter.core.enums.BaseEnum;
/**
* 任务触发类型枚举
*
* @author Charles7c
* @since 2024/7/11 22:28
*/
@Getter
@RequiredArgsConstructor
public enum JobTriggerTypeEnum implements BaseEnum<Integer> {
/**
* 固定时间
*/
FIXED_TIME(2, "固定时间"),
/**
* CRON
*/
CRON(3, "CRON");
private final Integer value;
private final String description;
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
import java.io.Serial;
import java.io.Serializable;
/**
* 任务实例日志分页信息
*
* @author Charles7c
* @since 2024/7/14 21:51
*/
@Data
@Schema(description = "任务实例日志分页信息")
public class JobInstanceLogPageResult implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(description = "ID", example = "1")
private Long id;
/**
* 日志详情
*/
@Schema(description = "日志详情")
private List message;
/**
* 异常信息
*/
@Schema(description = "异常信息")
private String throwable;
/**
* 是否结束
*/
@Schema(description = "是否结束", example = "true")
private boolean isFinished;
/**
* 起始索引
*/
@Schema(description = "起始索引", example = "0")
private Integer fromIndex;
/**
* 下一个开始 ID
*/
@Schema(description = "下一个开始ID", example = "9")
private Long nextStartId;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model;
import com.aizuda.snailjob.common.core.model.Result;
import lombok.Data;
/**
* 任务调度服务端分页返回对象
*
* @author KAI
* @author Charles7c
* @since 2024/6/26 22:27
*/
@Data
public class JobPageResult<T> extends Result<T> {
/**
* 页码
*/
private long page;
/**
* 每页条数
*/
private long size;
/**
* 总条数
*/
private long total;
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.query;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import java.io.Serial;
import java.io.Serializable;
/**
* 任务实例日志查询条件
*
* @author KAI
* @since 2024/6/28 16:58
*/
@Data
@Schema(description = "任务实例日志查询条件")
public class JobInstanceLogQuery implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务 ID
*/
@Schema(description = "任务ID", example = "1")
private Long jobId;
/**
* 任务批次 ID
*/
@Schema(description = "任务批次ID", example = "1")
private Long taskBatchId;
/**
* 任务实例 ID
*/
@Schema(description = "任务实例ID", example = "1")
private Long taskId;
/**
* 开始 ID
*/
@Schema(description = "开始ID", example = "2850")
private Integer startId;
/**
* 起始索引
*/
@Schema(description = "起始索引", example = "0")
@Min(value = 0, message = "起始索引最小值为 {value}")
private Integer fromIndex = 0;
/**
* 每页条数
*/
@Schema(description = "每页条数", example = "50")
@Range(min = 1, max = 1000, message = "每页条数(取值范围 {min}-{max}")
private Integer size = 50;
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.query;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 任务实例查询条件
*
* @author KAI
* @since 2024/6/28 16:58
*/
@Data
@Schema(description = "任务实例查询条件")
public class JobInstanceQuery implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务 ID
*/
@Schema(description = "任务ID", example = "1")
private Long jobId;
/**
* 任务批次 ID
*/
@Schema(description = "任务批次ID", example = "1")
private Long taskBatchId;
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.query;
import cn.hutool.core.date.DatePattern;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Size;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import org.springframework.format.annotation.DateTimeFormat;
import top.continew.admin.schedule.enums.JobExecuteStatusEnum;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 任务日志查询条件
*
* @author KAI
* @since 2024/6/27 23:58
*/
@Data
@Schema(description = "任务日志查询条件")
public class JobLogQuery implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务 ID
*/
@Schema(description = "任务ID", example = "1")
private Long jobId;
/**
* 任务组
*/
@Schema(description = "任务组", example = "continew-admin")
private String groupName;
/**
* 任务名称
*/
@Schema(description = "任务名称", example = "定时任务1")
private String jobName;
/**
* 任务批次状态
*/
@Schema(description = "任务批次状态", example = "1")
private JobExecuteStatusEnum taskBatchStatus;
/**
* 创建时间
*/
@Schema(description = "创建时间", example = "2023-08-08 00:00:00,2023-08-08 23:59:59")
@DateTimeFormat(pattern = DatePattern.NORM_DATETIME_PATTERN)
@Size(max = 2, message = "创建时间必须是一个范围")
private LocalDateTime[] datetimeRange;
/**
* 页码
*/
@Schema(description = "页码", example = "1")
@Min(value = 1, message = "页码最小值为 {value}")
private Integer page = 1;
/**
* 每页条数
*/
@Schema(description = "每页条数", example = "10")
@Range(min = 1, max = 1000, message = "每页条数(取值范围 {min}-{max}")
private Integer size = 10;
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.query;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import top.continew.admin.schedule.enums.JobStatusEnum;
import java.io.Serial;
import java.io.Serializable;
/**
* 任务查询条件
*
* @author KAI
* @since 2024/6/25 16:43
*/
@Data
@Schema(description = "任务查询条件")
public class JobQuery implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务组
*/
@Schema(description = "任务组", example = "continew-admin")
private String groupName;
/**
* 任务名称
*/
@Schema(description = "任务名称", example = "定时任务1")
private String jobName;
/**
* 任务状态
*/
@Schema(description = "任务状态", example = "1")
private JobStatusEnum jobStatus;
/**
* 页码
*/
@Schema(description = "页码", example = "1")
@Min(value = 1, message = "页码最小值为 {value}")
private Integer page = 1;
/**
* 每页条数
*/
@Schema(description = "每页条数", example = "10")
@Range(min = 1, max = 1000, message = "每页条数(取值范围 {min}-{max}")
private Integer size = 10;
}

View File

@@ -0,0 +1,163 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import top.continew.admin.schedule.enums.*;
import java.io.Serial;
import java.io.Serializable;
/**
* 创建或修改任务信息
*
* @author KAI
* @author Charles7c
* @since 2024/6/25 16:40
*/
@Data
@Schema(description = "创建或修改任务信息")
public class JobReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务组
*/
@Schema(description = "任务组", example = "continew-admin")
@NotBlank(message = "任务组不能为空")
private String groupName;
/**
* 任务名称
*/
@Schema(description = "任务名称", example = "定时任务1")
@NotBlank(message = "任务名称不能为空")
@Length(max = 64, message = "任务名称不能超过 {max} 个字符")
private String jobName;
/**
* 描述
*/
@Schema(description = "描述", example = "定时任务1的描述")
private String description;
/**
* 触发类型
*/
@Schema(description = "触发类型", example = "2")
@NotNull(message = "触发类型非法")
private JobTriggerTypeEnum triggerType;
/**
* 间隔时长
*/
@Schema(description = "间隔时长", example = "60")
@NotBlank(message = "间隔时长不能为空")
private String triggerInterval;
/**
* 执行器类型
*/
@Schema(description = "执行器类型", example = "1", defaultValue = "1")
private Integer executorType = 1;
/**
* 任务类型
*/
@Schema(description = "任务类型", example = "1")
@NotNull(message = "任务类型非法")
private JobTaskTypeEnum taskType;
/**
* 执行器名称
*/
@Schema(description = "执行器名称", example = "test")
@NotBlank(message = "执行器名称不能为空")
private String executorInfo;
/**
* 任务参数
*/
@Schema(description = "任务参数", example = "")
private String argsStr;
/**
* 参数类型
*/
@Schema(description = "参数类型", example = "1")
private Integer argsType;
/**
* 路由策略
*/
@Schema(description = "路由策略", example = "4")
@NotNull(message = "路由策略非法")
private JobRouteStrategyEnum routeKey;
/**
* 阻塞策略
*/
@Schema(description = "阻塞策略", example = "1")
@NotNull(message = "阻塞策略非法")
private JobBlockStrategyEnum blockStrategy;
/**
* 超时时间(单位:秒)
*/
@Schema(description = "超时时间(单位:秒)", example = "60")
@NotNull(message = "超时时间不能为空")
private Integer executorTimeout;
/**
* 最大重试次数
*/
@Schema(description = "最大重试次数", example = "3")
@NotNull(message = "最大重试次数不能为空")
private Integer maxRetryTimes;
/**
* 重试间隔(单位:秒)
*/
@Schema(description = "重试间隔(单位:秒)", example = "1")
@NotNull(message = "重试间隔不能为空")
private Integer retryInterval;
/**
* 并行数
*/
@Schema(description = "并行数", example = "1")
@NotNull(message = "并行数不能为空")
private Integer parallelNum;
/**
* 任务状态
*/
@Schema(description = "任务状态", example = "0", defaultValue = "0")
private JobStatusEnum jobStatus = JobStatusEnum.DISABLED;
/**
* ID
*/
@Schema(hidden = true)
private Long id;
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import top.continew.admin.schedule.enums.JobStatusEnum;
import java.io.Serial;
import java.io.Serializable;
/**
* 修改任务状态信息
*
* @author KAI
* @author Charles7c
* @since 2024/6/27 9:24
*/
@Data
@Schema(description = "修改任务状态信息")
public class JobStatusReq implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务状态
*/
@Schema(description = "任务状态", example = "1")
@NotNull(message = "任务状态非法")
private JobStatusEnum jobStatus;
/**
* ID
*/
@Schema(hidden = true)
private Long id;
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 任务实例信息
*
* @author KAI
* @author Charles7c
* @since 2024/6/28 16:58
*/
@Data
@Schema(description = "任务实例信息")
public class JobInstanceResp implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(description = "ID", example = "1")
private Long id;
/**
* 任务组
*/
@Schema(description = "任务组", example = "continew-admin")
private String groupName;
/**
* 任务 ID
*/
@Schema(description = "任务ID", example = "1")
private Long jobId;
/**
* 任务批次 ID
*/
@Schema(description = "任务批次ID", example = "1")
private Long taskBatchId;
/**
* 执行状态
*/
@Schema(description = "执行状态", example = "1")
private Integer taskStatus;
/**
* 重试次数
*/
@Schema(description = "重试次数", example = "1")
private Integer retryCount;
/**
* 执行结果
*/
@Schema(description = "执行结果", example = "")
private String resultMessage;
/**
* 客户端信息
*/
@Schema(description = "客户端信息", example = "1812406095098114048@192.168.138.48:1789")
private String clientInfo;
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import top.continew.admin.schedule.enums.JobExecuteReasonEnum;
import top.continew.admin.schedule.enums.JobExecuteStatusEnum;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 任务日志信息
*
* @author KAI
* @author Charles7c
* @since 2024/6/27 22:50
*/
@Data
@Schema(description = "任务日志信息")
public class JobLogResp implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(description = "ID", example = "1")
private Long id;
/**
* 任务组
*/
@Schema(description = "任务组", example = "continew-admin")
private String groupName;
/**
* 任务名称
*/
@Schema(description = "任务名称", example = "定时任务1")
private String jobName;
/**
* 任务 ID
*/
@Schema(description = "任务ID", example = "1")
private Long jobId;
/**
* 任务状态
*/
@Schema(description = "任务状态", example = "3")
private JobExecuteStatusEnum taskBatchStatus;
/**
* 操作原因
*/
@Schema(description = "操作原因", example = "0")
private JobExecuteReasonEnum operationReason;
/**
* 执行器类型
*/
@Schema(description = "执行器类型", example = "1")
private Integer executorType;
/**
* 执行器名称
*/
@Schema(description = "执行器名称", example = "test")
private String executorInfo;
/**
* 执行时间
*/
@Schema(description = "执行时间", example = "2023-08-08 08:08:08", type = "string")
private LocalDateTime executionAt;
/**
* 创建时间
*/
@Schema(description = "创建时间", example = "2023-08-08 08:08:08", type = "string")
private LocalDateTime createDt;
}

View File

@@ -0,0 +1,166 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.model.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import top.continew.admin.schedule.enums.*;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 任务信息
*
* @author KAI
* @author Charles7c
* @since 2024/6/25 17:15
*/
@Data
@Schema(description = "任务信息")
public class JobResp implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(description = "ID", example = "1")
private Long id;
/**
* 任务组
*/
@Schema(description = "任务组", example = "continew-admin")
private String groupName;
/**
* 任务名称
*/
@Schema(description = "任务名称", example = "定时任务1")
private String jobName;
/**
* 描述
*/
@Schema(description = "描述", example = "定时任务1的描述")
private String description;
/**
* 触发类型
*/
@Schema(description = "触发类型", example = "2")
private JobTriggerTypeEnum triggerType;
/**
* 间隔时长
*/
@Schema(description = "间隔时长", example = "60")
private String triggerInterval;
/**
* 执行器类型
*/
@Schema(description = " 执行器类型", example = "1")
private Integer executorType;
/**
* 任务类型
*/
@Schema(description = "任务类型", example = "1")
private JobTaskTypeEnum taskType;
/**
* 执行器名称
*/
@Schema(description = "执行器名称", example = "test")
private String executorInfo;
/**
* 任务参数
*/
@Schema(description = "任务参数", example = "")
private String argsStr;
/**
* 参数类型
*/
@Schema(description = "参数类型", example = "1")
private String argsType;
/**
* 路由策略
*/
@Schema(description = "路由策略", example = "1")
private JobRouteStrategyEnum routeKey;
/**
* 阻塞策略
*/
@Schema(description = "阻塞策略", example = "1")
private JobBlockStrategyEnum blockStrategy;
/**
* 超时时间(单位:秒)
*/
@Schema(description = "超时时间(单位:秒)", example = "60")
private Integer executorTimeout;
/**
* 最大重试次数
*/
@Schema(description = "最大重试次数", example = "3")
private Integer maxRetryTimes;
/**
* 重试间隔(单位:秒)
*/
@Schema(description = "重试间隔", example = "1")
private Integer retryInterval;
/**
* 并行数
*/
@Schema(description = "并行数", example = "1")
private Integer parallelNum;
/**
* 任务状态
*/
@Schema(description = "任务状态", example = "1")
private JobStatusEnum jobStatus;
/**
* 下次触发时间
*/
@Schema(description = "下次触发时间", example = "2023-08-08 08:09:00", type = "string")
private LocalDateTime nextTriggerAt;
/**
* 创建时间
*/
@Schema(description = "创建时间", example = "2023-08-08 08:08:00", type = "string")
private LocalDateTime createDt;
/**
* 修改时间
*/
@Schema(description = "修改时间", example = "2023-08-08 08:08:00", type = "string")
private LocalDateTime updateDt;
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.service;
import top.continew.admin.schedule.model.JobInstanceLogPageResult;
import top.continew.admin.schedule.model.query.JobInstanceLogQuery;
import top.continew.admin.schedule.model.query.JobLogQuery;
import top.continew.admin.schedule.model.query.JobInstanceQuery;
import top.continew.admin.schedule.model.resp.JobLogResp;
import top.continew.admin.schedule.model.resp.JobInstanceResp;
import top.continew.starter.extension.crud.model.resp.PageResp;
import java.util.List;
/**
* 任务日志业务接口
*
* @author KAI
* @author Charles7c
* @since 2024/6/27 22:52
*/
public interface JobLogService {
/**
* 分页查询列表
*
* @param query 查询条件
* @return 分页列表信息
*/
PageResp<JobLogResp> page(JobLogQuery query);
/**
* 停止
*
* @param id ID
* @return 停止结果
*/
boolean stop(Long id);
/**
* 重试
*
* @param id ID
* @return 重试结果
*/
boolean retry(Long id);
/**
* 查询任务实例列表
*
* @param query 查询条件
* @return 列表信息
*/
List<JobInstanceResp> listInstance(JobInstanceQuery query);
/**
* 分页查询任务实例日志列表
*
* @param query 查询条件
* @return 分页列表信息
*/
JobInstanceLogPageResult pageInstanceLog(JobInstanceLogQuery query);
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.service;
import top.continew.admin.schedule.model.query.JobQuery;
import top.continew.admin.schedule.model.req.JobReq;
import top.continew.admin.schedule.model.req.JobStatusReq;
import top.continew.admin.schedule.model.resp.JobResp;
import top.continew.starter.extension.crud.model.resp.PageResp;
import java.util.List;
/**
* 任务业务接口
*
* @author KAI
* @author Charles7c
* @since 2024/6/25 17:20
*/
public interface JobService {
/**
* 分页查询列表
*
* @param query 查询条件
* @return 分页列表信息
*/
PageResp<JobResp> page(JobQuery query);
/**
* 新增
*
* @param req 创建信息
* @return 新增结果
*/
boolean add(JobReq req);
/**
* 修改
*
* @param req 修改信息
* @param id ID
* @return 修改结果
*/
boolean update(JobReq req, Long id);
/**
* 修改状态
*
* @param req 修改状态信息
* @param id ID
* @return 修改状态结果
*/
boolean updateStatus(JobStatusReq req, Long id);
/**
* 删除
*
* @param id ID
* @return 删除结果
*/
boolean delete(Long id);
/**
* 执行
*
* @param id ID
* @return 执行结果
*/
boolean trigger(Long id);
/**
* 查询分组列表
*
* @return 分组列表
*/
List<String> listGroup();
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.service.impl;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import top.continew.admin.schedule.api.JobBatchApi;
import top.continew.admin.schedule.api.JobClient;
import top.continew.admin.schedule.model.JobInstanceLogPageResult;
import top.continew.admin.schedule.model.query.JobInstanceLogQuery;
import top.continew.admin.schedule.model.query.JobInstanceQuery;
import top.continew.admin.schedule.model.query.JobLogQuery;
import top.continew.admin.schedule.model.resp.JobInstanceResp;
import top.continew.admin.schedule.model.resp.JobLogResp;
import top.continew.admin.schedule.service.JobLogService;
import top.continew.starter.extension.crud.model.resp.PageResp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* 任务日志业务实现
*
* @author KAI
* @author Charles7c
* @since 2024/6/27 22:54
*/
@Service
@RequiredArgsConstructor
public class JobLogServiceImpl implements JobLogService {
private final JobClient jobClient;
private final JobBatchApi jobBatchApi;
@Override
public PageResp<JobLogResp> page(JobLogQuery query) {
LocalDateTime[] datetimeRange = query.getDatetimeRange();
return jobClient.requestPage(() -> jobBatchApi.page(query.getJobId(), query.getJobName(), query
.getGroupName(), query.getTaskBatchStatus() != null
? query.getTaskBatchStatus().getValue()
: null, new String[] {DateUtil.format(datetimeRange[0], DatePattern.UTC_SIMPLE_PATTERN), DateUtil
.format(datetimeRange[1], DatePattern.UTC_SIMPLE_PATTERN)}, query.getPage(), query.getSize()));
}
@Override
public boolean stop(Long id) {
return Boolean.TRUE.equals(jobClient.request(() -> jobBatchApi.stop(id)));
}
@Override
public boolean retry(Long id) {
return Boolean.TRUE.equals(jobClient.request(() -> jobBatchApi.retry(id)));
}
@Override
public List<JobInstanceResp> listInstance(JobInstanceQuery query) {
return jobClient.requestPage(() -> jobBatchApi.pageTask(query.getJobId(), query.getTaskBatchId(), 1, 100))
.getList();
}
@Override
public JobInstanceLogPageResult pageInstanceLog(JobInstanceLogQuery query) {
return Objects.requireNonNull(jobBatchApi.pageLog(query.getJobId(), query.getTaskBatchId(), query
.getTaskId(), query.getStartId(), query.getFromIndex(), query.getSize()).getBody()).getData();
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.schedule.service.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import top.continew.admin.schedule.api.JobApi;
import top.continew.admin.schedule.api.JobClient;
import top.continew.admin.schedule.model.query.JobQuery;
import top.continew.admin.schedule.model.req.JobReq;
import top.continew.admin.schedule.model.req.JobStatusReq;
import top.continew.admin.schedule.model.resp.JobResp;
import top.continew.admin.schedule.service.JobService;
import top.continew.starter.extension.crud.model.resp.PageResp;
import java.util.Collections;
import java.util.List;
/**
* 任务业务实现
*
* @author KAI
* @author Charles7c
* @since 2024/6/25 17:25
*/
@Service
@RequiredArgsConstructor
public class JobServiceImpl implements JobService {
private final JobClient jobClient;
private final JobApi jobApi;
@Override
public PageResp<JobResp> page(JobQuery query) {
return jobClient.requestPage(() -> jobApi.page(query.getGroupName(), query.getJobName(), query
.getJobStatus() != null ? query.getJobStatus().getValue() : null, query.getPage(), query.getSize()));
}
@Override
public boolean add(JobReq req) {
return Boolean.TRUE.equals(jobClient.request(() -> jobApi.add(req)));
}
@Override
public boolean update(JobReq req, Long id) {
req.setId(id);
return Boolean.TRUE.equals(jobClient.request(() -> jobApi.update(req)));
}
@Override
public boolean updateStatus(JobStatusReq req, Long id) {
req.setId(id);
return Boolean.TRUE.equals(jobClient.request(() -> jobApi.updateStatus(req)));
}
@Override
public boolean delete(Long id) {
return Boolean.TRUE.equals(jobClient.request(() -> jobApi.delete(Collections.singleton(id))));
}
@Override
public boolean trigger(Long id) {
return Boolean.TRUE.equals(jobClient.request(() -> jobApi.trigger(id)));
}
@Override
public List<String> listGroup() {
return jobClient.request(jobApi::listGroup);
}
}