feat:2.5.0

1. 支持手动触发任务
2. 支持手动停止任务
This commit is contained in:
byteblogs168 2023-11-17 23:34:20 +08:00
parent 008629b60d
commit 3907e27b8a
12 changed files with 140 additions and 22 deletions

View File

@ -23,6 +23,7 @@ public enum JobOperationReasonEnum {
JOB_OVERLAY(5, "任务被覆盖"), JOB_OVERLAY(5, "任务被覆盖"),
NOT_EXECUTE_TASK(6, "无可执行任务项"), NOT_EXECUTE_TASK(6, "无可执行任务项"),
TASK_EXECUTE_ERROR(7, "任务执行期间发生非预期异常"), TASK_EXECUTE_ERROR(7, "任务执行期间发生非预期异常"),
MANNER_STOP(8, "手动停止"),
; ;
private final int reason; private final int reason;

View File

@ -3,15 +3,10 @@ package com.aizuda.easy.retry.server.web.controller;
import com.aizuda.easy.retry.server.web.annotation.LoginRequired; import com.aizuda.easy.retry.server.web.annotation.LoginRequired;
import com.aizuda.easy.retry.server.web.model.base.PageResult; import com.aizuda.easy.retry.server.web.model.base.PageResult;
import com.aizuda.easy.retry.server.web.model.request.JobBatchQueryVO; import com.aizuda.easy.retry.server.web.model.request.JobBatchQueryVO;
import com.aizuda.easy.retry.server.web.model.request.JobQueryVO;
import com.aizuda.easy.retry.server.web.model.response.JobBatchResponseVO; import com.aizuda.easy.retry.server.web.model.response.JobBatchResponseVO;
import com.aizuda.easy.retry.server.web.model.response.JobResponseVO;
import com.aizuda.easy.retry.server.web.service.JobBatchService; import com.aizuda.easy.retry.server.web.service.JobBatchService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
@ -39,5 +34,10 @@ public class JobBatchController {
return jobBatchService.getJobBatchDetail(id); return jobBatchService.getJobBatchDetail(id);
} }
@PostMapping("/stop/{taskBatchId}")
@LoginRequired
public Boolean stop(@PathVariable("taskBatchId") Long taskBatchId) {
return jobBatchService.stop(taskBatchId);
}
} }

View File

@ -77,4 +77,10 @@ public class JobController {
) { ) {
return jobService.getJobNameList(keywords, jobId); return jobService.getJobNameList(keywords, jobId);
} }
@PostMapping("/trigger/{jobId}")
@LoginRequired
public Boolean trigger(@PathVariable("jobId") Long jobId) {
return jobService.trigger(jobId);
}
} }

View File

@ -16,4 +16,7 @@ public interface JobBatchService {
PageResult<List<JobBatchResponseVO>> getJobBatchPage(JobBatchQueryVO jobQueryVO); PageResult<List<JobBatchResponseVO>> getJobBatchPage(JobBatchQueryVO jobQueryVO);
JobBatchResponseVO getJobBatchDetail(Long id); JobBatchResponseVO getJobBatchDetail(Long id);
boolean stop(Long taskBatchId);
} }

View File

@ -32,4 +32,7 @@ public interface JobService {
List<String> getTimeByCron(String cron); List<String> getTimeByCron(String cron);
List<JobResponseVO> getJobNameList(String keywords, Long jobId); List<JobResponseVO> getJobNameList(String keywords, Long jobId);
boolean trigger(Long jobId);
} }

View File

@ -1,7 +1,17 @@
package com.aizuda.easy.retry.server.web.service.impl; package com.aizuda.easy.retry.server.web.service.impl;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.aizuda.easy.retry.common.core.enums.JobOperationReasonEnum;
import com.aizuda.easy.retry.common.core.enums.StatusEnum; import com.aizuda.easy.retry.common.core.enums.StatusEnum;
import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException;
import com.aizuda.easy.retry.server.common.util.DateUtils;
import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO;
import com.aizuda.easy.retry.server.job.task.support.JobPrePareHandler;
import com.aizuda.easy.retry.server.job.task.support.JobTaskConverter;
import com.aizuda.easy.retry.server.job.task.support.JobTaskStopHandler;
import com.aizuda.easy.retry.server.job.task.support.stop.JobTaskStopFactory;
import com.aizuda.easy.retry.server.job.task.support.stop.TaskStopJobContext;
import com.aizuda.easy.retry.server.web.model.base.PageResult; import com.aizuda.easy.retry.server.web.model.base.PageResult;
import com.aizuda.easy.retry.server.web.model.request.JobBatchQueryVO; import com.aizuda.easy.retry.server.web.model.request.JobBatchQueryVO;
import com.aizuda.easy.retry.server.web.model.response.JobBatchResponseVO; import com.aizuda.easy.retry.server.web.model.response.JobBatchResponseVO;
@ -16,6 +26,7 @@ import com.aizuda.easy.retry.template.datasource.persistence.po.JobTaskBatch;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
@ -47,10 +58,10 @@ public class JobBatchServiceImpl implements JobBatchService {
jobBatchQueryDO.setJobId(queryVO.getJobId()); jobBatchQueryDO.setJobId(queryVO.getJobId());
jobBatchQueryDO.setTaskBatchStatus(queryVO.getTaskBatchStatus()); jobBatchQueryDO.setTaskBatchStatus(queryVO.getTaskBatchStatus());
jobBatchQueryDO.setGroupName(queryVO.getGroupName()); jobBatchQueryDO.setGroupName(queryVO.getGroupName());
List<JobBatchResponseDO> batchResponseDOList = jobTaskBatchMapper.selectJobBatchList(pageDTO, jobBatchQueryDO); List<JobBatchResponseDO> batchResponseDOList = jobTaskBatchMapper.selectJobBatchList(pageDTO, jobBatchQueryDO);
List<JobBatchResponseVO> batchResponseVOList = JobBatchResponseVOConverter.INSTANCE.toJobBatchResponseVOs( List<JobBatchResponseVO> batchResponseVOList = JobBatchResponseVOConverter.INSTANCE.toJobBatchResponseVOs(
batchResponseDOList); batchResponseDOList);
return new PageResult<>(pageDTO, batchResponseVOList); return new PageResult<>(pageDTO, batchResponseVOList);
} }
@ -65,4 +76,29 @@ public class JobBatchServiceImpl implements JobBatchService {
Job job = jobMapper.selectById(jobTaskBatch.getJobId()); Job job = jobMapper.selectById(jobTaskBatch.getJobId());
return JobBatchResponseVOConverter.INSTANCE.toJobBatchResponseVO(jobTaskBatch, job); return JobBatchResponseVOConverter.INSTANCE.toJobBatchResponseVO(jobTaskBatch, job);
} }
@Override
public boolean stop(Long taskBatchId) {
JobTaskBatch jobTaskBatch = jobTaskBatchMapper.selectById(taskBatchId);
Assert.notNull(jobTaskBatch, () -> new EasyRetryServerException("job batch can not be null."));
Job job = jobMapper.selectById(jobTaskBatch.getJobId());
Assert.notNull(job, () -> new EasyRetryServerException("job can not be null."));
JobTaskStopHandler jobTaskStop = JobTaskStopFactory.getJobTaskStop(job.getTaskType());
TaskStopJobContext taskStopJobContext = new TaskStopJobContext();
taskStopJobContext.setJobId(job.getId());
taskStopJobContext.setTaskType(job.getTaskType());
taskStopJobContext.setGroupName(job.getGroupName());
taskStopJobContext.setJobOperationReason(JobOperationReasonEnum.MANNER_STOP.getReason());
taskStopJobContext.setTaskBatchId(jobTaskBatch.getId());
taskStopJobContext.setForceStop(Boolean.TRUE);
taskStopJobContext.setNeedUpdateTaskStatus(Boolean.TRUE);
jobTaskStop.stop(taskStopJobContext);
return Boolean.TRUE;
}
} }

View File

@ -10,6 +10,9 @@ import com.aizuda.easy.retry.server.common.exception.EasyRetryServerException;
import com.aizuda.easy.retry.server.common.strategy.WaitStrategies; import com.aizuda.easy.retry.server.common.strategy.WaitStrategies;
import com.aizuda.easy.retry.server.common.util.CronUtils; import com.aizuda.easy.retry.server.common.util.CronUtils;
import com.aizuda.easy.retry.server.common.util.DateUtils; import com.aizuda.easy.retry.server.common.util.DateUtils;
import com.aizuda.easy.retry.server.job.task.dto.JobTaskPrepareDTO;
import com.aizuda.easy.retry.server.job.task.support.JobPrePareHandler;
import com.aizuda.easy.retry.server.job.task.support.JobTaskConverter;
import com.aizuda.easy.retry.server.job.task.support.cache.ResidentTaskCache; import com.aizuda.easy.retry.server.job.task.support.cache.ResidentTaskCache;
import com.aizuda.easy.retry.server.web.model.base.PageResult; import com.aizuda.easy.retry.server.web.model.base.PageResult;
import com.aizuda.easy.retry.server.web.model.request.JobQueryVO; import com.aizuda.easy.retry.server.web.model.request.JobQueryVO;
@ -25,6 +28,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -42,11 +46,13 @@ import java.util.Optional;
@Slf4j @Slf4j
public class JobServiceImpl implements JobService { public class JobServiceImpl implements JobService {
private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Autowired @Autowired
private SystemProperties systemProperties; private SystemProperties systemProperties;
@Autowired @Autowired
private JobMapper jobMapper; private JobMapper jobMapper;
@Autowired
@Qualifier("terminalJobPrepareHandler")
private JobPrePareHandler jobPrePareHandler;
@Override @Override
public PageResult<List<JobResponseVO>> getJobPage(JobQueryVO queryVO) { public PageResult<List<JobResponseVO>> getJobPage(JobQueryVO queryVO) {
@ -190,4 +196,19 @@ public class JobServiceImpl implements JobService {
job.setDeleted(StatusEnum.YES.getStatus()); job.setDeleted(StatusEnum.YES.getStatus());
return 1 == jobMapper.updateById(job); return 1 == jobMapper.updateById(job);
} }
@Override
public boolean trigger(Long jobId) {
Job job = jobMapper.selectById(jobId);
Assert.notNull(job, () -> new EasyRetryServerException("job can not be null."));
JobTaskPrepareDTO jobTaskPrepare = JobTaskConverter.INSTANCE.toJobTaskPrepare(job);
// 设置now表示立即执行
jobTaskPrepare.setNextTriggerAt(DateUtils.toNowMilli());
// 创建批次
jobPrePareHandler.handler(jobTaskPrepare);
return Boolean.TRUE;
}
} }

View File

@ -9,10 +9,12 @@ const jobApi = {
delJob: '/job/', delJob: '/job/',
timeByCron: '/job/cron', timeByCron: '/job/cron',
jobNameList: '/job/job-name/list', jobNameList: '/job/job-name/list',
triggerJob: '/job/trigger/',
// 任务批次 // 任务批次
jobBatchList: '/job/batch/list', jobBatchList: '/job/batch/list',
jobBatchDetail: '/job/batch/', jobBatchDetail: '/job/batch/',
stop: '/job/batch/stop/',
// 任务 // 任务
jobTaskList: '/job/task/list', jobTaskList: '/job/task/list',
@ -23,6 +25,20 @@ const jobApi = {
export default jobApi export default jobApi
export function triggerJob (id) {
return request({
url: jobApi.triggerJob + id,
method: 'post'
})
}
export function stop (id) {
return request({
url: jobApi.stop + id,
method: 'post'
})
}
export function jobNameList (parameter) { export function jobNameList (parameter) {
return request({ return request({
url: jobApi.jobNameList, url: jobApi.jobNameList,

View File

@ -128,6 +128,10 @@ const enums = {
'7': { '7': {
'name': '任务执行期间发生非预期异常', 'name': '任务执行期间发生非预期异常',
'color': '#bdc223' 'color': '#bdc223'
},
'8': {
'name': '手动停止',
'color': '#23c28a'
} }
}, },
taskStatus: { taskStatus: {

View File

@ -111,6 +111,14 @@
<template> <template>
<a @click="handleInfo(record)">详情</a> <a @click="handleInfo(record)">详情</a>
<a-divider type="vertical" /> <a-divider type="vertical" />
<a-popconfirm
title="是否停止?"
ok-text="停止"
cancel-text="取消"
@confirm="handleStop(record)"
>
<a href="javascript:;" v-if="record.taskBatchStatus === 1 || record.taskBatchStatus === 2">停止</a>
</a-popconfirm>
<!-- <a-popconfirm--> <!-- <a-popconfirm-->
<!-- title="是否暂停?"--> <!-- title="是否暂停?"-->
<!-- ok-text="恢复"--> <!-- ok-text="恢复"-->
@ -158,7 +166,7 @@
import ATextarea from 'ant-design-vue/es/input/TextArea' import ATextarea from 'ant-design-vue/es/input/TextArea'
import AInput from 'ant-design-vue/es/input/Input' import AInput from 'ant-design-vue/es/input/Input'
import { STable } from '@/components' import { STable } from '@/components'
import { jobBatchList, jobNameList } from '@/api/jobApi' import { jobBatchList, jobNameList, stop } from '@/api/jobApi'
import { getAllGroupNameList } from '@/api/manage' import { getAllGroupNameList } from '@/api/manage'
const enums = require('@/utils/jobEnum') const enums = require('@/utils/jobEnum')
@ -301,16 +309,16 @@ export default {
this.$router.push({ path: '/job/batch/info', query: { id: record.id, groupName: record.groupName } }) this.$router.push({ path: '/job/batch/info', query: { id: record.id, groupName: record.groupName } })
}, },
handleOk (record) {}, handleOk (record) {},
handleSuspend (record) { handleStop (record) {
// updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 3 }).then((res) => { stop(record.id).then((res) => {
// const { status } = res const { status } = res
// if (status === 0) { if (status === 0) {
// this.$message.error('') this.$message.error('停止失败')
// } else { } else {
// this.$refs.table.refresh(true) this.$refs.table.refresh(true)
// this.$message.success('') this.$message.success('停止成功')
// } }
// }) })
}, },
handleRecovery (record) { handleRecovery (record) {
// updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 0 }).then((res) => { // updateRetryTaskStatus({ id: record.id, groupName: record.groupName, retryStatus: 0 }).then((res) => {

View File

@ -111,6 +111,15 @@
</span> </span>
<span slot="action" slot-scope="text, record"> <span slot="action" slot-scope="text, record">
<template> <template>
<a-popconfirm
title="是否运行?"
ok-text="运行"
cancel-text="取消"
@confirm="handleTrigger(record)"
>
<a href="javascript:;">运行</a>
</a-popconfirm>
<a-divider type="vertical" />
<a @click="handleInfo(record)">详情</a> <a @click="handleInfo(record)">详情</a>
<a-divider type="vertical" /> <a-divider type="vertical" />
<a @click="goJobBatchList(record)">批次</a> <a @click="goJobBatchList(record)">批次</a>
@ -155,7 +164,7 @@
import ATextarea from 'ant-design-vue/es/input/TextArea' import ATextarea from 'ant-design-vue/es/input/TextArea'
import AInput from 'ant-design-vue/es/input/Input' import AInput from 'ant-design-vue/es/input/Input'
import { STable } from '@/components' import { STable } from '@/components'
import { delJob, getJobList, updateJobStatus } from '@/api/jobApi' import { delJob, getJobList, triggerJob, updateJobStatus } from '@/api/jobApi'
import { getAllGroupNameList } from '@/api/manage' import { getAllGroupNameList } from '@/api/manage'
import enums from '@/utils/jobEnum' import enums from '@/utils/jobEnum'
@ -311,6 +320,17 @@ export default {
} }
}) })
}, },
handleTrigger (record) {
triggerJob(record.id).then((res) => {
const { status } = res
if (status === 0) {
this.$message.error('执行失败')
} else {
// this.$refs.table.refresh(true)
this.$message.success('执行成功')
}
})
},
handleOpen (record) { handleOpen (record) {
updateJobStatus({ id: record.id, jobStatus: 1 }).then((res) => { updateJobStatus({ id: record.id, jobStatus: 1 }).then((res) => {
const { status } = res const { status } = res

View File

@ -106,7 +106,7 @@
<a-divider type="vertical" /> <a-divider type="vertical" />
<a-popconfirm <a-popconfirm
title="是否暂停?" title="是否暂停?"
ok-text="恢复" ok-text="暂停"
cancel-text="取消" cancel-text="取消"
@confirm="handleSuspend(record)" @confirm="handleSuspend(record)"
> >