feat: 新增任务调度模块

SnailJob(灵活,可靠和快速的分布式任务重试和分布式任务调度平台)
This commit is contained in:
KAI
2024-07-18 07:20:00 +00:00
committed by Charles7c
parent b587cb82aa
commit ce1acea153
51 changed files with 8845 additions and 20 deletions

View File

@@ -25,6 +25,25 @@
</properties>
<dependencies>
<!-- 系统管理模块(存放系统管理模块相关功能,例如:部门管理、角色管理、用户管理等) -->
<dependency>
<groupId>top.continew</groupId>
<artifactId>continew-admin-system</artifactId>
</dependency>
<!-- 代码生成器插件(后续会改造为独立插件) -->
<dependency>
<groupId>top.continew</groupId>
<artifactId>continew-admin-generator</artifactId>
</dependency>
<!-- 任务调度插件(后续会改造为独立插件) -->
<dependency>
<groupId>top.continew</groupId>
<artifactId>continew-admin-job</artifactId>
<version>${revision}</version>
</dependency>
<!-- Liquibase用于管理数据库版本跟踪、管理和应用数据库变化 -->
<dependency>
<groupId>org.liquibase</groupId>
@@ -36,18 +55,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 代码生成器插件(后续会改造为独立插件) -->
<dependency>
<groupId>top.continew</groupId>
<artifactId>continew-admin-generator</artifactId>
</dependency>
<!-- 系统管理模块(存放系统管理模块相关功能,例如:部门管理、角色管理、用户管理等) -->
<dependency>
<groupId>top.continew</groupId>
<artifactId>continew-admin-system</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,108 @@
/*
* 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.controller.schedule;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.job.model.query.JobQuery;
import top.continew.admin.job.model.req.JobReq;
import top.continew.admin.job.model.req.JobStatusReq;
import top.continew.admin.job.model.resp.JobResp;
import top.continew.admin.job.service.JobService;
import top.continew.starter.extension.crud.model.resp.PageResp;
import top.continew.starter.extension.crud.util.ValidateGroup;
import top.continew.starter.log.core.annotation.Log;
import top.continew.starter.web.model.R;
import java.util.List;
/**
* 任务 API
*
* @author KAI
* @author Charles7c
* @since 2024/6/25 22:24
*/
@Tag(name = " 任务 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/schedule/job")
public class JobController {
private final JobService baseService;
@Operation(summary = "分页查询任务列表", description = "分页查询任务列表")
@SaCheckPermission("schedule:job:list")
@GetMapping
public R<PageResp<JobResp>> page(JobQuery query) {
return R.ok(baseService.page(query));
}
@Operation(summary = "新增任务", description = "新增任务")
@SaCheckPermission("schedule:job:add")
@PostMapping
public R<Void> add(@Validated(ValidateGroup.Crud.Add.class) @RequestBody JobReq req) {
return baseService.add(req) ? R.ok() : R.fail();
}
@Operation(summary = "修改任务", description = "修改任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:job:update")
@PutMapping("/{id}")
public R<Void> update(@Validated(ValidateGroup.Crud.Update.class) @RequestBody JobReq req, @PathVariable Long id) {
return baseService.update(req, id) ? R.ok() : R.fail();
}
@Operation(summary = "修改任务状态", description = "修改任务状态")
@SaCheckPermission("schedule:job:update")
@PatchMapping("/{id}/status")
public R<Void> updateStatus(@Validated @RequestBody JobStatusReq req, @PathVariable Long id) {
return baseService.updateStatus(req, id) ? R.ok() : R.fail();
}
@Operation(summary = "删除任务", description = "删除任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:job:delete")
@DeleteMapping("/{id}")
public R<Void> delete(@PathVariable Long id) {
return baseService.delete(id) ? R.ok() : R.fail();
}
@Operation(summary = "执行任务", description = "执行任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:job:trigger")
@PostMapping("/trigger/{id}")
public R<Void> trigger(@PathVariable Long id) {
return baseService.trigger(id) ? R.ok() : R.fail();
}
@Log(ignore = true)
@Operation(summary = "查询任务分组列表", description = "查询任务分组列表")
@SaCheckPermission("schedule:job:list")
@GetMapping("/group")
public R<List<String>> listGroup() {
List<String> groupList = baseService.listGroup();
return R.ok(groupList);
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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.controller.schedule;
import cn.dev33.satoken.annotation.SaCheckPermission;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import top.continew.admin.job.model.JobInstanceLogPageResult;
import top.continew.admin.job.model.query.JobInstanceLogQuery;
import top.continew.admin.job.model.query.JobLogQuery;
import top.continew.admin.job.model.query.JobInstanceQuery;
import top.continew.admin.job.model.resp.JobLogResp;
import top.continew.admin.job.model.resp.JobInstanceResp;
import top.continew.admin.job.service.JobLogService;
import top.continew.starter.extension.crud.model.resp.PageResp;
import top.continew.starter.web.model.R;
import java.util.List;
/**
* 任务日志 API
*
* @author KAI
* @author Charles7c
* @since 2024/6/27 22:24
*/
@Tag(name = " 任务日志 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/schedule/log")
public class JobLogController {
private final JobLogService baseService;
@Operation(summary = "分页查询任务日志列表", description = "分页查询任务日志列表")
@SaCheckPermission("schedule:log:list")
@GetMapping
public R<PageResp<JobLogResp>> page(JobLogQuery query) {
return R.ok(baseService.page(query));
}
@Operation(summary = "停止任务", description = "停止任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:log:stop")
@PostMapping("/stop/{id}")
public R<Void> stop(@PathVariable Long id) {
return baseService.stop(id) ? R.ok() : R.fail();
}
@Operation(summary = "重试任务", description = "重试任务")
@Parameter(name = "id", description = "ID", example = "1", in = ParameterIn.PATH)
@SaCheckPermission("schedule:log:retry")
@PostMapping("/retry/{id}")
public R<Void> retry(@PathVariable Long id) {
return baseService.retry(id) ? R.ok() : R.fail();
}
@Operation(summary = "查询任务实例列表", description = "查询任务实例列表")
@SaCheckPermission("schedule:log:list")
@GetMapping("/instance")
public R<List<JobInstanceResp>> listInstance(JobInstanceQuery query) {
return R.ok(baseService.listInstance(query));
}
@Operation(summary = "分页查询任务实例日志列表", description = "分页查询任务实例日志列表")
@SaCheckPermission("schedule:log:list")
@GetMapping("/instance/log")
public R<JobInstanceLogPageResult> pageInstanceLog(JobInstanceLogQuery query) {
return R.ok(baseService.pageInstanceLog(query));
}
}

View File

@@ -286,3 +286,51 @@ spring.servlet:
## 头像支持格式配置
avatar:
support-suffix: jpg,jpeg,png,gif
--- ### Snail Job 配置
snail-job:
# 分组名
group: continew-admin
# 客户端地址(默认自动获取本机 IP
#host: 127.0.0.1
# 客户端端口默认1789
port: 1789
# 名称空间 ID
namespace: 764d604ec6fc45f68cd92514c40e9e1a
# 令牌
token: SJ_Wyz3dmsdbDOkDujOTSSoBjGQP1BMsVnj
## 服务端配置
server:
# 服务端地址
url: http://127.0.0.1:8001/snail-job
# 服务端用户名
username: admin
# 服务端密码
password: admin
# 服务端地址,若服务端集群部署则此处配置域名
host: 127.0.0.1
# 服务端端口号
port: 1788
## 重试数据批量上报滑动窗口配置
retry:
reportSlidingWindow:
# 窗口期单位
chrono-unit: SECONDS
# 窗口期时间长度
duration: 10
# 总量窗口期阈值
total-threshold: 50
# 窗口数量预警
window-total-threshold: 150
## 调度线程池配置
dispatcherThreadPool:
# 核心线程数
corePoolSize: 16
# 最大线程数
maximumPoolSize: 16
# 线程存活时间
keepAliveTime: 1
# 时间单位
timeUnit: SECONDS
# 队列容量
queueCapacity: 10000

View File

@@ -283,3 +283,51 @@ spring.servlet:
## 头像支持格式配置
avatar:
support-suffix: jpg,jpeg,png,gif
--- ### Snail Job 配置
snail-job:
# 分组名
group: continew_admin
# 客户端地址(默认自动获取本机 IP
#host: 127.0.0.1
# 客户端端口默认1789
port: 1789
# 名称空间 ID
namespace: 764d604ec6fc45f68cd92514c40e9e1a
# 令牌
token: SJ_Wyz3dmsdbDOkDujOTSSoBjGQP1BMsVnj
## 服务端配置
server:
# 服务端地址
url: http://127.0.0.1:8001/snail-job
# 服务端用户名
username: admin
# 服务端密码
password: admin
# 服务端地址,若服务端集群部署则此处配置域名
host: 127.0.0.1
# 服务端端口号
port: 1788
## 重试数据批量上报滑动窗口配置
retry:
reportSlidingWindow:
# 窗口期单位
chrono-unit: SECONDS
# 窗口期时间长度
duration: 10
# 总量窗口期阈值
total-threshold: 50
# 窗口数量预警
window-total-threshold: 150
## 调度线程池配置
dispatcherThreadPool:
# 核心线程数
corePoolSize: 16
# 最大线程数
maximumPoolSize: 16
# 线程存活时间
keepAliveTime: 1
# 时间单位
timeUnit: SECONDS
# 队列容量
queueCapacity: 10000

View File

@@ -122,10 +122,12 @@ mybatis-plus:
mapper-locations: classpath*:/mapper/**/*Mapper.xml
# 类型别名扫描包配置
type-aliases-package: ${project.base-package}.**.model
## MyBatis 配置
configuration:
# MyBatis 自动映射策略
# NONE不启用 PARTIAL只对非嵌套 resultMap 自动映射 FULL对所有 resultMap 自动映射
auto-mapping-behavior: PARTIAL
## 全局配置
global-config:
banner: true
db-config:

View File

@@ -172,4 +172,19 @@ INSERT INTO `sys_storage`
(`id`, `name`, `code`, `type`, `access_key`, `secret_key`, `endpoint`, `bucket_name`, `domain`, `description`, `is_default`, `sort`, `status`, `create_user`, `create_time`, `update_user`, `update_time`)
VALUES
(1, '开发环境', 'local_dev', 2, NULL, NULL, NULL, 'C:/continew-admin/data/file/', 'http://localhost:8000/file', '本地存储', b'1', 1, 1, 1, NOW(), NULL, NULL),
(2, '生产环境', 'local_prod', 2, NULL, NULL, NULL, '../data/file/', 'http://api.continew.top/file', '本地存储', b'0', 2, 2, 1, NOW(), NULL, NULL);
(2, '生产环境', 'local_prod', 2, NULL, NULL, NULL, '../data/file/', 'http://api.continew.top/file', '本地存储', b'0', 2, 2, 1, NOW(), NULL, NULL);
-- changeset Kai:3.2-1
INSERT INTO `sys_menu` (`id`, `title`, `parent_id`, `type`, `path`, `name`, `component`, `redirect`, `icon`, `is_external`, `is_cache`, `is_hidden`, `permission`, `sort`, `status`, `create_user`, `create_time`, `update_user`, `update_time`)
VALUES
(4000, '任务调度', 0, 1, '/schedule', 'Schedule', 'Layout', '/schedule/job', 'schedule', b'0', b'0', b'0', NULL, 997, 1, 1, NOW(), NULL, NULL),
(4010, '任务管理', 4000, 2, '/schedule/job', 'ScheduleJob', 'schedule/job/index', NULL, 'select-all', b'0', b'0', b'0', NULL, 1, 1, 1, NOW(), NULL, NULL),
(4011, '查看', 4010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:list', 1, 1, 1, NOW(), NULL, NULL),
(4012, '新增', 4010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:add', 2, 1, 1, NOW(), NULL, NULL),
(4013, '修改', 4010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:update', 3, 1, 1, NOW(), NULL, NULL),
(4014, '删除', 4010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:delete', 4, 1, 1, NOW(), NULL, NULL),
(4015, '执行', 1010, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:job:trigger', 5, 1, 1, NOW(), NULL, NULL),
(4020, '任务日志', 4000, 2, '/schedule/log', 'ScheduleLog', 'schedule/log/index', NULL, 'find-replace', b'0', b'0', b'0', NULL, 2, 1, 1, NOW(), NULL, NULL),
(4021, '查看', 4020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:list', 1, 1, 1, NOW(), NULL, NULL),
(4022, '停止', 4020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:stop', 2, 1, 1, NOW(), NULL, NULL),
(4023, '重试', 4020, 3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'schedule:log:retry', 3, 1, 1, NOW(), NULL, NULL);