mirror of
https://github.com/whyour/qinglong.git
synced 2025-07-27 14:46:06 +08:00
增加停止定时任务功能
This commit is contained in:
parent
fa3d73ac9a
commit
5ef327692b
|
@ -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({
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -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}`);
|
||||||
|
|
|
@ -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>项
|
||||||
|
|
Loading…
Reference in New Issue
Block a user