diff --git a/db/4pigxx_job.sql b/db/4pigxx_job.sql index fa3277d9f..abe139fb8 100644 --- a/db/4pigxx_job.sql +++ b/db/4pigxx_job.sql @@ -270,7 +270,8 @@ CREATE TABLE `sys_job` ( `next_time` timestamp NULL DEFAULT NULL COMMENT '下次执行时间', `tenant_id` bigint DEFAULT '1' COMMENT '租户', `remark` varchar(500) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '备注信息', - PRIMARY KEY (`job_id`,`job_name`,`job_group`) USING BTREE + PRIMARY KEY (`job_id`) USING BTREE, + UNIQUE KEY `job_name_group_idx` (`job_name`,`job_group`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时任务调度表'; -- ---------------------------- diff --git a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/controller/SysJobController.java b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/controller/SysJobController.java index 9ba132597..5a1ecaf32 100644 --- a/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/controller/SysJobController.java +++ b/pigx-visual/pigx-daemon-quartz/src/main/java/com/pig4cloud/pigx/daemon/quartz/controller/SysJobController.java @@ -36,7 +36,9 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.quartz.Scheduler; +import org.quartz.SchedulerException; import org.springframework.http.HttpHeaders; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; @@ -44,8 +46,8 @@ import org.springframework.web.bind.annotation.*; import java.util.List; /** - * @author frwcloud - * @date 2019-01-27 10:04:42 + * @author guoliang + * @date 2024-3-26 11:19:18 *

* 定时任务管理 */ @@ -54,258 +56,293 @@ import java.util.List; @RequestMapping("/sys-job") @Tag(description = "sys-job", name = "定时任务") @SecurityRequirement(name = HttpHeaders.AUTHORIZATION) +@Slf4j public class SysJobController { - private final SysJobService sysJobService; + private final SysJobService sysJobService; - private final SysJobLogService sysJobLogService; + private final SysJobLogService sysJobLogService; - private final TaskUtil taskUtil; + private final TaskUtil taskUtil; - private final Scheduler scheduler; + private final Scheduler scheduler; - /** - * 定时任务分页查询 - * @param page 分页对象 - * @param sysJob 定时任务调度表 - * @return - */ - @GetMapping("/page") - @Operation(description = "分页定时业务查询") - public R getSysJobPage(Page page, SysJob sysJob) { - LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() - .like(StrUtil.isNotBlank(sysJob.getJobName()), SysJob::getJobName, sysJob.getJobName()) - .like(StrUtil.isNotBlank(sysJob.getJobGroup()), SysJob::getJobGroup, sysJob.getJobGroup()) - .eq(StrUtil.isNotBlank(sysJob.getJobStatus()), SysJob::getJobStatus, sysJob.getJobGroup()) - .eq(StrUtil.isNotBlank(sysJob.getJobExecuteStatus()), SysJob::getJobExecuteStatus, - sysJob.getJobExecuteStatus()); - return R.ok(sysJobService.page(page, wrapper)); - } + /** + * 定时任务分页查询 + * + * @param page 分页对象 + * @param sysJob 定时任务调度表 + * @return R + */ + @GetMapping("/page") + @Operation(description = "分页定时业务查询") + public R getSysJobPage(Page page, SysJob sysJob) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .like(StrUtil.isNotBlank(sysJob.getJobName()), SysJob::getJobName, sysJob.getJobName()) + .like(StrUtil.isNotBlank(sysJob.getJobGroup()), SysJob::getJobGroup, sysJob.getJobGroup()) + .eq(StrUtil.isNotBlank(sysJob.getJobStatus()), SysJob::getJobStatus, sysJob.getJobGroup()) + .eq(StrUtil.isNotBlank(sysJob.getJobExecuteStatus()), SysJob::getJobExecuteStatus, + sysJob.getJobExecuteStatus()); + return R.ok(sysJobService.page(page, wrapper)); + } - /** - * 通过id查询定时任务 - * @param id id - * @return R - */ - @GetMapping("/{id}") - @Operation(description = "唯一标识查询定时任务") - public R getById(@PathVariable("id") Long id) { - return R.ok(sysJobService.getById(id)); - } + /** + * 通过id查询定时任务 + * + * @param id id + * @return R + */ + @GetMapping("/{id}") + @Operation(description = "唯一标识查询定时任务") + public R getById(@PathVariable("id") Long id) { + return R.ok(sysJobService.getById(id)); + } - /** - * 新增定时任务 - * @param sysJob 定时任务调度表 - * @return R - */ - @SysLog("新增定时任务") - @PostMapping - @PreAuthorize("@pms.hasPermission('job_sys_job_add')") - @Operation(description = "新增定时任务") - public R save(@RequestBody SysJob sysJob) { - // 初始化任务 - taskUtil.addOrUpateJob(sysJob, scheduler); - sysJob.setJobStatus(PigxQuartzEnum.JOB_STATUS_RELEASE.getType()); - sysJob.setCreateBy(SecurityUtils.getUser().getUsername()); - return R.ok(sysJobService.save(sysJob)); - } + /** + * 新增定时任务,默认新增状态为1已发布 + * + * @param sysJob 定时任务调度表 + * @return R + */ + @SysLog("新增定时任务") + @PostMapping + @PreAuthorize("@pms.hasPermission('job_sys_job_add')") + @Operation(description = "新增定时任务") + public R save(@RequestBody SysJob sysJob) { + long count = sysJobService + .count(Wrappers.query( + SysJob.builder() + .jobName(sysJob.getJobName()) + .jobGroup(sysJob.getJobGroup()) + .build() + )); - /** - * 修改定时任务 - * @param sysJob 定时任务调度表 - * @return R - */ - @SysLog("修改定时任务") - @PutMapping - @PreAuthorize("@pms.hasPermission('job_sys_job_edit')") - @Operation(description = "修改定时任务") - public R updateById(@RequestBody SysJob sysJob) { - sysJob.setUpdateBy(SecurityUtils.getUser().getUsername()); - SysJob querySysJob = this.sysJobService.getById(sysJob.getJobId()); - if (PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(querySysJob.getJobStatus())) { - this.taskUtil.addOrUpateJob(sysJob, scheduler); - sysJobService.updateById(sysJob); - } - else if (PigxQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) { - sysJobService.updateById(sysJob); - } - return R.ok(); - } + if (count > 0) { + return R.failed("任务重复,请检查此组内是否已包含同名任务"); + } + sysJob.setJobStatus(PigxQuartzEnum.JOB_STATUS_RELEASE.getType()); + sysJob.setCreateBy(SecurityUtils.getUser().getUsername()); + return R.ok(sysJobService.save(sysJob)); + } - /** - * 通过id删除定时任务 - * @param id id - * @return R - */ - @SysLog("删除定时任务") - @DeleteMapping("/{id}") - @PreAuthorize("@pms.hasPermission('job_sys_job_del')") - @Operation(description = "唯一标识查询定时任务,暂停任务才能删除") - public R removeById(@PathVariable Long id) { - SysJob querySysJob = this.sysJobService.getById(id); - if (PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(querySysJob.getJobStatus())) { - this.taskUtil.removeJob(querySysJob, scheduler); - this.sysJobService.removeById(id); - } - else if (PigxQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) { - this.sysJobService.removeById(id); - } - return R.ok(); - } + /** + * 修改定时任务 + * + * @param sysJob 定时任务调度表 + * @return R + */ + @SysLog("修改定时任务") + @PutMapping + @PreAuthorize("@pms.hasPermission('job_sys_job_edit')") + @Operation(description = "修改定时任务") + public R updateById(@RequestBody SysJob sysJob) { + sysJob.setUpdateBy(SecurityUtils.getUser().getUsername()); + SysJob querySysJob = this.sysJobService.getById(sysJob.getJobId()); + if (PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(querySysJob.getJobStatus())) { + //如修改暂停的需更新调度器 + this.taskUtil.addOrUpateJob(sysJob, scheduler); + sysJobService.updateById(sysJob); + } else if (PigxQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) { + sysJobService.updateById(sysJob); + } + return R.ok(); + } - /** - * 暂停全部定时任务 - * @return - */ - @SysLog("暂停全部定时任务") - @PostMapping("/shutdown-jobs") - @PreAuthorize("@pms.hasPermission('job_sys_job_shutdown_job')") - @Operation(description = "暂停全部定时任务") - public R shutdownJobs() { - taskUtil.pauseJobs(scheduler); - long count = this.sysJobService.count( - new LambdaQueryWrapper().eq(SysJob::getJobStatus, PigxQuartzEnum.JOB_STATUS_RUNNING.getType())); - if (count <= 0) { - return R.ok("无正在运行定时任务"); - } - else { - // 更新定时任务状态条件,运行状态2更新为暂停状态2 - this.sysJobService.update( - SysJob.builder().jobStatus(PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()).build(), - new UpdateWrapper().lambda().eq(SysJob::getJobStatus, - PigxQuartzEnum.JOB_STATUS_RUNNING.getType())); - return R.ok("暂停成功"); - } - } + /** + * 通过id删除定时任务 + * + * @param id id + * @return R + */ + @SysLog("删除定时任务") + @DeleteMapping("/{id}") + @PreAuthorize("@pms.hasPermission('job_sys_job_del')") + @Operation(description = "唯一标识查询定时任务,暂停任务才能删除") + public R removeById(@PathVariable Long id) { + SysJob querySysJob = this.sysJobService.getById(id); + if (PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(querySysJob.getJobStatus())) { + this.taskUtil.removeJob(querySysJob, scheduler); + this.sysJobService.removeById(id); + } else if (PigxQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) { + this.sysJobService.removeById(id); + } + return R.ok(); + } - /** - * 启动全部定时任务 - * @return - */ - @SysLog("启动全部定时任务") - @PostMapping("/start-jobs") - @PreAuthorize("@pms.hasPermission('job_sys_job_start_job')") - @Operation(description = "启动全部定时任务") - public R startJobs() { - // 更新定时任务状态条件,暂停状态3更新为运行状态2 - this.sysJobService.update(SysJob.builder().jobStatus(PigxQuartzEnum.JOB_STATUS_RUNNING.getType()).build(), - new UpdateWrapper().lambda().eq(SysJob::getJobStatus, - PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType())); - taskUtil.startJobs(scheduler); - return R.ok(); - } + /** + * 暂停全部定时任务 + * + * @return R + */ + @SysLog("暂停全部定时任务") + @PostMapping("/shutdown-jobs") + @PreAuthorize("@pms.hasPermission('job_sys_job_shutdown_job')") + @Operation(description = "暂停全部定时任务") + public R shutdownJobs() { + taskUtil.pauseJobs(scheduler); + long count = this.sysJobService.count( + new LambdaQueryWrapper().eq(SysJob::getJobStatus, PigxQuartzEnum.JOB_STATUS_RUNNING.getType())); + if (count <= 0) { + return R.ok("无正在运行定时任务"); + } else { + // 更新定时任务状态条件,运行状态2更新为暂停状态3 + this.sysJobService.update( + SysJob.builder().jobStatus(PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()).build(), + new UpdateWrapper().lambda().eq(SysJob::getJobStatus, + PigxQuartzEnum.JOB_STATUS_RUNNING.getType())); + return R.ok("暂停成功"); + } + } - /** - * 刷新全部定时任务 - * @return - */ - @SysLog("刷新全部定时任务") - @PostMapping("/refresh-jobs") - @PreAuthorize("@pms.hasPermission('job_sys_job_refresh_job')") - @Operation(description = "刷新全部定时任务") - public R refreshJobs() { - sysJobService.list().forEach((sysjob) -> { - if (PigxQuartzEnum.JOB_STATUS_RELEASE.getType().equals(sysjob.getJobStatus()) - || PigxQuartzEnum.JOB_STATUS_DEL.getType().equals(sysjob.getJobStatus())) { - taskUtil.removeJob(sysjob, scheduler); - } - else if (PigxQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysjob.getJobStatus()) - || PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysjob.getJobStatus())) { - taskUtil.addOrUpateJob(sysjob, scheduler); - } - else { - taskUtil.removeJob(sysjob, scheduler); - } - }); - return R.ok(); - } + /** + * 启动全部定时任务 + * + * @return + */ + @SysLog("启动全部暂停的定时任务") + @PostMapping("/start-jobs") + @PreAuthorize("@pms.hasPermission('job_sys_job_start_job')") + @Operation(description = "启动全部暂停的定时任务") + public R startJobs() { + // 更新定时任务状态条件,暂停状态3更新为运行状态2 + this.sysJobService.update(SysJob.builder().jobStatus(PigxQuartzEnum.JOB_STATUS_RUNNING.getType()).build(), + new UpdateWrapper().lambda().eq(SysJob::getJobStatus, + PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType())); + taskUtil.startJobs(scheduler); + return R.ok(); + } - /** - * 启动定时任务 - * @param jobId - * @return - */ - @SysLog("启动定时任务") - @PostMapping("/start-job/{id}") - @PreAuthorize("@pms.hasPermission('job_sys_job_start_job')") - @Operation(description = "启动定时任务") - public R startJob(@PathVariable("id") Long jobId) { - SysJob querySysJob = this.sysJobService.getById(jobId); - if (querySysJob != null && PigxQuartzEnum.JOB_LOG_STATUS_FAIL.getType().equals(querySysJob.getJobStatus())) { - taskUtil.addOrUpateJob(querySysJob, scheduler); - } - else { - taskUtil.resumeJob(querySysJob, scheduler); - } - // 更新定时任务状态条件,暂停状态3更新为运行状态2 - this.sysJobService.updateById( - SysJob.builder().jobId(jobId).jobStatus(PigxQuartzEnum.JOB_STATUS_RUNNING.getType()).build()); - return R.ok(); - } + /** + * 刷新全部定时任务 + * 暂停和运行的添加到调度器其他状态从调度器移除 + * + * @return R + */ + @SysLog("刷新全部定时任务") + @PostMapping("/refresh-jobs") + @PreAuthorize("@pms.hasPermission('job_sys_job_refresh_job')") + @Operation(description = "刷新全部定时任务") + public R refreshJobs() { + sysJobService.list().forEach(sysjob -> { + if (PigxQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysjob.getJobStatus()) + || PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysjob.getJobStatus())) { + taskUtil.addOrUpateJob(sysjob, scheduler); + } else { + taskUtil.removeJob(sysjob, scheduler); + } + }); + return R.ok(); + } - /** - * 启动定时任务 - * @param jobId - * @return - */ - @SysLog("立刻执行定时任务") - @PostMapping("/run-job/{id}") - @PreAuthorize("@pms.hasPermission('job_sys_job_run_job')") - @Operation(description = "立刻执行定时任务") - public R runJob(@PathVariable("id") Long jobId) { - SysJob querySysJob = this.sysJobService.getById(jobId); - return TaskUtil.runOnce(scheduler, querySysJob) ? R.ok() : R.failed(); - } + /** + * 启动定时任务 + * + * @param jobId 任务id + * @return R + */ + @SysLog("启动定时任务") + @PostMapping("/start-job/{id}") + @PreAuthorize("@pms.hasPermission('job_sys_job_start_job')") + @Operation(description = "启动定时任务") + public R startJob(@PathVariable("id") Long jobId) throws SchedulerException { + SysJob querySysJob = this.sysJobService.getById(jobId); + if (querySysJob == null) { + return R.failed("无此定时任务,请确认"); + } - /** - * 暂停定时任务 - * @return - */ - @SysLog("暂停定时任务") - @PostMapping("/shutdown-job/{id}") - @PreAuthorize("@pms.hasPermission('job_sys_job_shutdown_job')") - @Operation(description = "暂停定时任务") - public R shutdownJob(@PathVariable("id") Long id) { - SysJob querySysJob = this.sysJobService.getById(id); - // 更新定时任务状态条件,运行状态2更新为暂停状态3 - this.sysJobService.updateById(SysJob.builder().jobId(querySysJob.getJobId()) - .jobStatus(PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()).build()); - taskUtil.pauseJob(querySysJob, scheduler); - return R.ok(); - } + //如果定时任务不存在,强制状态为1已发布 + if (!scheduler.checkExists(TaskUtil.getJobKey(querySysJob))) { + querySysJob.setJobStatus(PigxQuartzEnum.JOB_STATUS_RELEASE.getType()); + log.warn("定时任务不在quartz中,任务id:{},强制状态为已发布并加入调度器", jobId); + } - /** - * 唯一标识查询定时执行日志 - * @return - */ - @GetMapping("/job-log") - @Operation(description = "唯一标识查询定时执行日志") - public R getJobLog(Page page, SysJobLog sysJobLog) { - return R.ok(sysJobLogService.page(page, Wrappers.query(sysJobLog))); - } + if (PigxQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) { + taskUtil.addOrUpateJob(querySysJob, scheduler); + } else { + taskUtil.resumeJob(querySysJob, scheduler); + } + // 更新定时任务状态为运行状态2 + this.sysJobService.updateById( + SysJob.builder().jobId(jobId).jobStatus(PigxQuartzEnum.JOB_STATUS_RUNNING.getType()).build()); + return R.ok(); + } - /** - * 检验任务名称和任务组联合是否唯一 - * @return - */ - @GetMapping("/is-valid-task-name") - @Operation(description = "检验任务名称和任务组联合是否唯一") - public R isValidTaskName(@RequestParam String jobName, @RequestParam String jobGroup) { - return this.sysJobService - .count(Wrappers.query(SysJob.builder().jobName(jobName).jobGroup(jobGroup).build())) > 0 - ? R.failed("任务重复,请检查此组内是否已包含同名任务") : R.ok(); - } + /** + * 启动定时任务 + * + * @param jobId 任务id + * @return R + */ + @SysLog("立刻执行定时任务") + @PostMapping("/run-job/{id}") + @PreAuthorize("@pms.hasPermission('job_sys_job_run_job')") + @Operation(description = "立刻执行定时任务") + public R runJob(@PathVariable("id") Long jobId) throws SchedulerException { + SysJob querySysJob = this.sysJobService.getById(jobId); - /** - * 导出任务 - * @param sysJob - * @return - */ - @ResponseExcel - @GetMapping("/export") - @Operation(description = "导出任务") - public List export(SysJob sysJob) { - return sysJobService.list(Wrappers.query(sysJob)); - } + //执行定时任务前判定任务是否在quartz中 + if (!scheduler.checkExists(TaskUtil.getJobKey(querySysJob))) { + querySysJob.setJobStatus(PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()); + log.warn("立刻执行定时任务-定时任务不在quartz中,任务id:{},强制状态为暂停并加入调度器", jobId); + taskUtil.addOrUpateJob(querySysJob, scheduler); + } + + return TaskUtil.runOnce(scheduler, querySysJob) ? R.ok() : R.failed(); + } + + /** + * 暂停定时任务 + * + * @return + */ + @SysLog("暂停定时任务") + @PostMapping("/shutdown-job/{id}") + @PreAuthorize("@pms.hasPermission('job_sys_job_shutdown_job')") + @Operation(description = "暂停定时任务") + public R shutdownJob(@PathVariable("id") Long id) { + SysJob querySysJob = this.sysJobService.getById(id); + // 更新定时任务状态条件,运行状态2更新为暂停状态3 + this.sysJobService.updateById(SysJob.builder().jobId(querySysJob.getJobId()) + .jobStatus(PigxQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()).build()); + taskUtil.pauseJob(querySysJob, scheduler); + return R.ok(); + } + + /** + * 唯一标识查询定时执行日志 + * + * @return + */ + @GetMapping("/job-log") + @Operation(description = "唯一标识查询定时执行日志") + public R getJobLog(Page page, SysJobLog sysJobLog) { + return R.ok(sysJobLogService.page(page, Wrappers.query(sysJobLog))); + } + + /** + * 检验任务名称和任务组联合是否唯一 + * + * @return + */ + @GetMapping("/is-valid-task-name") + @Operation(description = "检验任务名称和任务组联合是否唯一") + public R isValidTaskName(@RequestParam String jobName, @RequestParam String jobGroup) { + return this.sysJobService + .count(Wrappers.query(SysJob.builder().jobName(jobName).jobGroup(jobGroup).build())) > 0 + ? R.failed("任务重复,请检查此组内是否已包含同名任务") : R.ok(); + } + + /** + * 导出任务 + * + * @param sysJob + * @return + */ + @ResponseExcel + @GetMapping("/export") + @Operation(description = "导出任务") + public List export(SysJob sysJob) { + return sysJobService.list(Wrappers.query(sysJob)); + } }