mirror of
https://github.com/whyour/qinglong.git
synced 2025-07-27 14:28:47 +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(
|
||||
'/crons/disable',
|
||||
celebrate({
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -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}`);
|
||||
|
|
|
@ -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) => (
|
||||
<Space size="middle">
|
||||
<Tooltip title="运行">
|
||||
<a
|
||||
onClick={() => {
|
||||
runCron(record, index);
|
||||
}}
|
||||
>
|
||||
<PlayCircleOutlined />
|
||||
</a>
|
||||
</Tooltip>
|
||||
{record.status !== CrontabStatus.running && (
|
||||
<Tooltip title="运行">
|
||||
<a
|
||||
onClick={() => {
|
||||
runCron(record, index);
|
||||
}}
|
||||
>
|
||||
<PlayCircleOutlined />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
{record.status === CrontabStatus.running && (
|
||||
<Tooltip title="停止">
|
||||
<a
|
||||
onClick={() => {
|
||||
stopCron(record, index);
|
||||
}}
|
||||
>
|
||||
<PauseCircleOutlined />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title="日志">
|
||||
<a
|
||||
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) => {
|
||||
Modal.confirm({
|
||||
title: `确认${
|
||||
|
@ -534,9 +586,16 @@ const Crontab = () => {
|
|||
>
|
||||
批量禁用
|
||||
</Button>
|
||||
<Button type="primary" onClick={() => operateCrons(2)}>
|
||||
<Button
|
||||
type="primary"
|
||||
style={{ marginRight: 8 }}
|
||||
onClick={() => operateCrons(2)}
|
||||
>
|
||||
批量运行
|
||||
</Button>
|
||||
<Button type="primary" onClick={() => operateCrons(3)}>
|
||||
批量停止
|
||||
</Button>
|
||||
<span style={{ marginLeft: 8 }}>
|
||||
已选择
|
||||
<a>{selectedRowIds?.length}</a>项
|
||||
|
|
Loading…
Reference in New Issue
Block a user