From 5ef327692b59afc72ff9eca14fd5443db76f9c13 Mon Sep 17 00:00:00 2001 From: whyour Date: Mon, 10 May 2021 15:45:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=81=9C=E6=AD=A2=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/api/cron.ts | 18 +++++++++ back/data/cron.ts | 2 + back/loaders/initData.ts | 4 +- back/services/cron.ts | 24 ++++++++++- src/pages/crontab/index.tsx | 79 ++++++++++++++++++++++++++++++++----- 5 files changed, 114 insertions(+), 13 deletions(-) diff --git a/back/api/cron.ts b/back/api/cron.ts index b69f366c..702ebbeb 100644 --- a/back/api/cron.ts +++ b/back/api/cron.ts @@ -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( '/crons/disable', celebrate({ diff --git a/back/data/cron.ts b/back/data/cron.ts index 9c6e96ad..39d7f1b0 100644 --- a/back/data/cron.ts +++ b/back/data/cron.ts @@ -8,6 +8,7 @@ export class Crontab { _id?: string; status?: CrontabStatus; isSystem?: 1 | 0; + pid?: number; constructor(options: Crontab) { this.name = options.name; @@ -19,6 +20,7 @@ export class Crontab { this.status = options.status || CrontabStatus.idle; this.timestamp = new Date().toString(); this.isSystem = options.isSystem || 0; + this.pid = options.pid; } } diff --git a/back/loaders/initData.ts b/back/loaders/initData.ts index 2fb67bb8..0753cccc 100644 --- a/back/loaders/initData.ts +++ b/back/loaders/initData.ts @@ -22,13 +22,13 @@ const initData = [ name: '删除日志', command: 'ql rmlog 7', schedule: '30 7 */7 * *', - status: CrontabStatus.disabled, + status: CrontabStatus.idle, }, { name: '互助码', command: 'ql code', schedule: '30 7 * * *', - status: CrontabStatus.disabled, + status: CrontabStatus.idle, }, ]; diff --git a/back/services/cron.ts b/back/services/cron.ts index b1853656..a8734424 100644 --- a/back/services/cron.ts +++ b/back/services/cron.ts @@ -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) { let { _id, command } = cron; @@ -140,7 +159,10 @@ export default class CronService { } 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) => { this.logger.silly(`stdout: ${data}`); diff --git a/src/pages/crontab/index.tsx b/src/pages/crontab/index.tsx index 6be6d27c..67a3a406 100644 --- a/src/pages/crontab/index.tsx +++ b/src/pages/crontab/index.tsx @@ -23,6 +23,7 @@ import { EditOutlined, StopOutlined, DeleteOutlined, + PauseCircleOutlined, } from '@ant-design/icons'; import config from '@/utils/config'; import { PageContainer } from '@ant-design/pro-layout'; @@ -43,12 +44,14 @@ enum OperationName { '启用', '禁用', '运行', + '停止', } enum OperationPath { 'enable', 'disable', 'run', + 'stop', } const Crontab = () => { @@ -120,15 +123,28 @@ const Crontab = () => { align: 'center' as const, render: (text: string, record: any, index: number) => ( - - { - runCron(record, index); - }} - > - - - + {record.status !== CrontabStatus.running && ( + + { + runCron(record, index); + }} + > + + + + )} + {record.status === CrontabStatus.running && ( + + { + stopCron(record, index); + }} + > + + + + )} { @@ -248,6 +264,42 @@ const Crontab = () => { }); }; + const stopCron = (record: any, index: number) => { + Modal.confirm({ + title: '确认停止', + content: ( + <> + 确认停止定时任务{' '} + + {record.name} + {' '} + 吗 + + ), + 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) => { Modal.confirm({ title: `确认${ @@ -534,9 +586,16 @@ const Crontab = () => { > 批量禁用 - + 已选择 {selectedRowIds?.length}