增加停止定时任务功能

This commit is contained in:
whyour 2021-05-10 15:45:52 +08:00
parent fa3d73ac9a
commit 5ef327692b
5 changed files with 114 additions and 13 deletions

View File

@ -69,6 +69,24 @@ export default (app: Router) => {
}, },
); );
route.put(
'/crons/stop',
celebrate({
body: Joi.array().items(Joi.string().required()),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
const cronService = Container.get(CronService);
const data = await cronService.stop(req.body);
return res.send({ code: 200, data });
} catch (e) {
logger.error('🔥 error: %o', e);
return next(e);
}
},
);
route.put( route.put(
'/crons/disable', '/crons/disable',
celebrate({ celebrate({

View File

@ -8,6 +8,7 @@ export class Crontab {
_id?: string; _id?: string;
status?: CrontabStatus; status?: CrontabStatus;
isSystem?: 1 | 0; isSystem?: 1 | 0;
pid?: number;
constructor(options: Crontab) { constructor(options: Crontab) {
this.name = options.name; this.name = options.name;
@ -19,6 +20,7 @@ export class Crontab {
this.status = options.status || CrontabStatus.idle; this.status = options.status || CrontabStatus.idle;
this.timestamp = new Date().toString(); this.timestamp = new Date().toString();
this.isSystem = options.isSystem || 0; this.isSystem = options.isSystem || 0;
this.pid = options.pid;
} }
} }

View File

@ -22,13 +22,13 @@ const initData = [
name: '删除日志', name: '删除日志',
command: 'ql rmlog 7', command: 'ql rmlog 7',
schedule: '30 7 */7 * *', schedule: '30 7 */7 * *',
status: CrontabStatus.disabled, status: CrontabStatus.idle,
}, },
{ {
name: '互助码', name: '互助码',
command: 'ql code', command: 'ql code',
schedule: '30 7 * * *', schedule: '30 7 * * *',
status: CrontabStatus.disabled, status: CrontabStatus.idle,
}, },
]; ];

View File

@ -121,6 +121,25 @@ export default class CronService {
}); });
} }
public async stop(ids: string[]) {
this.cronDb.find({ _id: { $in: ids } }).exec((err, docs: Crontab[]) => {
for (let i = 0; i < docs.length; i++) {
const doc = docs[i];
this.runSingle(doc);
if (doc.pid) {
exec(`kill -9 ${doc.pid}`, (err, stdout, stderr) => {
let logFile = `${config.manualLogPath}${doc._id}.log`;
this.cronDb.update(
{ _id: doc._id },
{ $set: { status: CrontabStatus.idle } },
);
fs.appendFileSync(logFile, `\n\n${stderr}\n${stdout}\n执行结束...`);
});
}
}
});
}
private async runSingle(cron: Crontab) { private async runSingle(cron: Crontab) {
let { _id, command } = cron; let { _id, command } = cron;
@ -140,7 +159,10 @@ export default class CronService {
} }
const cmd = spawn(cmdStr, { shell: true }); const cmd = spawn(cmdStr, { shell: true });
this.cronDb.update({ _id }, { $set: { status: CrontabStatus.running } }); this.cronDb.update(
{ _id },
{ $set: { status: CrontabStatus.running, pid: cmd.pid } },
);
cmd.stdout.on('data', (data) => { cmd.stdout.on('data', (data) => {
this.logger.silly(`stdout: ${data}`); this.logger.silly(`stdout: ${data}`);

View File

@ -23,6 +23,7 @@ import {
EditOutlined, EditOutlined,
StopOutlined, StopOutlined,
DeleteOutlined, DeleteOutlined,
PauseCircleOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import config from '@/utils/config'; import config from '@/utils/config';
import { PageContainer } from '@ant-design/pro-layout'; import { PageContainer } from '@ant-design/pro-layout';
@ -43,12 +44,14 @@ enum OperationName {
'启用', '启用',
'禁用', '禁用',
'运行', '运行',
'停止',
} }
enum OperationPath { enum OperationPath {
'enable', 'enable',
'disable', 'disable',
'run', 'run',
'stop',
} }
const Crontab = () => { const Crontab = () => {
@ -120,15 +123,28 @@ const Crontab = () => {
align: 'center' as const, align: 'center' as const,
render: (text: string, record: any, index: number) => ( render: (text: string, record: any, index: number) => (
<Space size="middle"> <Space size="middle">
<Tooltip title="运行"> {record.status !== CrontabStatus.running && (
<a <Tooltip title="运行">
onClick={() => { <a
runCron(record, index); onClick={() => {
}} runCron(record, index);
> }}
<PlayCircleOutlined /> >
</a> <PlayCircleOutlined />
</Tooltip> </a>
</Tooltip>
)}
{record.status === CrontabStatus.running && (
<Tooltip title="停止">
<a
onClick={() => {
stopCron(record, index);
}}
>
<PauseCircleOutlined />
</a>
</Tooltip>
)}
<Tooltip title="日志"> <Tooltip title="日志">
<a <a
onClick={() => { onClick={() => {
@ -248,6 +264,42 @@ const Crontab = () => {
}); });
}; };
const stopCron = (record: any, index: number) => {
Modal.confirm({
title: '确认停止',
content: (
<>
{' '}
<Text style={{ wordBreak: 'break-all' }} type="warning">
{record.name}
</Text>{' '}
</>
),
onOk() {
request
.put(`${config.apiPrefix}crons/stop`, { data: [record._id] })
.then((data: any) => {
if (data.code === 200) {
const result = [...value];
result.splice(index, 1, {
...record,
status: CrontabStatus.idle,
});
setValue(result);
} else {
notification.error({
message: data,
});
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const enabledOrDisabledCron = (record: any, index: number) => { const enabledOrDisabledCron = (record: any, index: number) => {
Modal.confirm({ Modal.confirm({
title: `确认${ title: `确认${
@ -534,9 +586,16 @@ const Crontab = () => {
> >
</Button> </Button>
<Button type="primary" onClick={() => operateCrons(2)}> <Button
type="primary"
style={{ marginRight: 8 }}
onClick={() => operateCrons(2)}
>
</Button> </Button>
<Button type="primary" onClick={() => operateCrons(3)}>
</Button>
<span style={{ marginLeft: 8 }}> <span style={{ marginLeft: 8 }}>
<a>{selectedRowIds?.length}</a> <a>{selectedRowIds?.length}</a>