定时任务增加运行任务前和运行任务后参数

This commit is contained in:
whyour 2023-09-19 22:44:32 +08:00
parent 8d899f1a53
commit ab3fc9b5f1
11 changed files with 88 additions and 36 deletions

View File

@ -177,6 +177,8 @@ export default (app: Router) => {
labels: Joi.array().optional(), labels: Joi.array().optional(),
sub_id: Joi.number().optional().allow(null), sub_id: Joi.number().optional().allow(null),
extra_schedules: Joi.array().optional().allow(null), extra_schedules: Joi.array().optional().allow(null),
task_before: Joi.string().optional().allow('').allow(null),
task_after: Joi.string().optional().allow('').allow(null),
}), }),
}), }),
async (req: Request, res: Response, next: NextFunction) => { async (req: Request, res: Response, next: NextFunction) => {
@ -335,6 +337,8 @@ export default (app: Router) => {
name: Joi.string().optional().allow(null), name: Joi.string().optional().allow(null),
sub_id: Joi.number().optional().allow(null), sub_id: Joi.number().optional().allow(null),
extra_schedules: Joi.array().optional().allow(null), extra_schedules: Joi.array().optional().allow(null),
task_before: Joi.string().optional().allow('').allow(null),
task_after: Joi.string().optional().allow('').allow(null),
id: Joi.number().required(), id: Joi.number().required(),
}), }),
}), }),

View File

@ -19,6 +19,8 @@ export class Crontab {
last_execution_time?: number; last_execution_time?: number;
sub_id?: number; sub_id?: number;
extra_schedules?: Array<{ schedule: string }>; extra_schedules?: Array<{ schedule: string }>;
task_before?: string;
task_after?: string;
constructor(options: Crontab) { constructor(options: Crontab) {
this.name = options.name; this.name = options.name;
@ -41,6 +43,8 @@ export class Crontab {
this.last_execution_time = options.last_execution_time || 0; this.last_execution_time = options.last_execution_time || 0;
this.sub_id = options.sub_id; this.sub_id = options.sub_id;
this.extra_schedules = options.extra_schedules; this.extra_schedules = options.extra_schedules;
this.task_before = options.task_before;
this.task_after = options.task_after;
} }
} }
@ -77,5 +81,7 @@ export const CrontabModel = sequelize.define<CronInstance>('Crontab', {
last_running_time: DataTypes.NUMBER, last_running_time: DataTypes.NUMBER,
last_execution_time: DataTypes.NUMBER, last_execution_time: DataTypes.NUMBER,
sub_id: { type: DataTypes.NUMBER, allowNull: true }, sub_id: { type: DataTypes.NUMBER, allowNull: true },
extra_schedules: DataTypes.JSON extra_schedules: DataTypes.JSON,
task_before: DataTypes.STRING,
task_after: DataTypes.STRING,
}); });

View File

@ -52,6 +52,12 @@ export default async () => {
try { try {
await sequelize.query('alter table Crontabs add column extra_schedules JSON'); await sequelize.query('alter table Crontabs add column extra_schedules JSON');
} catch (error) { } } catch (error) { }
try {
await sequelize.query('alter table Crontabs add column task_before TEXT');
} catch (error) { }
try {
await sequelize.query('alter table Crontabs add column task_after TEXT');
} catch (error) { }
// 2.10-2.11 升级 // 2.10-2.11 升级
const cronDbFile = path.join(config.rootPath, 'db/crontab.db'); const cronDbFile = path.join(config.rootPath, 'db/crontab.db');

View File

@ -16,11 +16,6 @@ const addCron = (
scheduleStacks.get(id)?.forEach((x) => x.cancel()); scheduleStacks.get(id)?.forEach((x) => x.cancel());
} }
let cmdStr = command.trim();
if (!cmdStr.startsWith(TASK_PREFIX) && !cmdStr.startsWith(QL_PREFIX)) {
cmdStr = `${TASK_PREFIX}${cmdStr}`;
}
Logger.info( Logger.info(
'[schedule][创建定时任务], 任务ID: %s, cron: %s, 执行命令: %s', '[schedule][创建定时任务], 任务ID: %s, cron: %s, 执行命令: %s',
id, id,
@ -41,14 +36,14 @@ const addCron = (
scheduleStacks.set(id, [ scheduleStacks.set(id, [
nodeSchedule.scheduleJob(id, schedule, async () => { nodeSchedule.scheduleJob(id, schedule, async () => {
Logger.info(`[schedule][准备运行任务] 命令: ${cmdStr}`); Logger.info(`[schedule][准备运行任务] 命令: ${command}`);
runCron(`ID=${id} ${cmdStr}`); runCron(command);
}), }),
...(extraSchedules?.length ...(extraSchedules?.length
? extraSchedules.map((x) => ? extraSchedules.map((x) =>
nodeSchedule.scheduleJob(id, x.schedule, async () => { nodeSchedule.scheduleJob(id, x.schedule, async () => {
Logger.info(`[schedule][准备运行任务] 命令: ${cmdStr}`); Logger.info(`[schedule][准备运行任务] 命令: ${command}`);
runCron(`ID=${id} ${cmdStr}`); runCron(command);
}), }),
) )
: []), : []),

View File

@ -33,7 +33,7 @@ export default class CronService {
const doc = await this.insert(tab); const doc = await this.insert(tab);
if (this.isSixCron(doc) || doc.extra_schedules?.length) { if (this.isSixCron(doc) || doc.extra_schedules?.length) {
await cronClient.addCron([ await cronClient.addCron([
{ id: String(doc.id), schedule: doc.schedule!, command: doc.command, extraSchedules: doc.extra_schedules || [] }, { id: String(doc.id), schedule: doc.schedule!, command: this.makeCommand(doc), extraSchedules: doc.extra_schedules || [] },
]); ]);
} }
await this.set_crontab(); await this.set_crontab();
@ -60,7 +60,7 @@ export default class CronService {
{ {
id: String(newDoc.id), id: String(newDoc.id),
schedule: newDoc.schedule!, schedule: newDoc.schedule!,
command: newDoc.command, command: this.makeCommand(newDoc),
extraSchedules: newDoc.extra_schedules || [] extraSchedules: newDoc.extra_schedules || []
}, },
]); ]);
@ -406,21 +406,7 @@ export default class CronService {
this.logger.silly('ID: ' + id); this.logger.silly('ID: ' + id);
this.logger.silly('Original command: ' + command); this.logger.silly('Original command: ' + command);
let cmdStr = command; const cp = spawn(`real_log_path=${logPath} no_delay=true ${this.makeCommand(cron)}`, { shell: '/bin/bash' });
if (!cmdStr.startsWith(TASK_PREFIX) && !cmdStr.startsWith(QL_PREFIX)) {
cmdStr = `${TASK_PREFIX}${cmdStr}`;
}
if (
cmdStr.endsWith('.js') ||
cmdStr.endsWith('.py') ||
cmdStr.endsWith('.pyc') ||
cmdStr.endsWith('.sh') ||
cmdStr.endsWith('.ts')
) {
cmdStr = `${cmdStr} now`;
}
const cp = spawn(`real_log_path=${logPath} ID=${id} ${cmdStr}`, { shell: '/bin/bash' });
await CrontabModel.update( await CrontabModel.update(
{ status: CrontabStatus.running, pid: cp.pid, log_path: logPath }, { status: CrontabStatus.running, pid: cp.pid, log_path: logPath },
@ -507,12 +493,22 @@ export default class CronService {
} }
} }
private make_command(tab: Crontab) { private makeCommand(tab: Crontab) {
let command = tab.command.trim(); let command = tab.command.trim();
if (!command.startsWith(TASK_PREFIX) && !command.startsWith(QL_PREFIX)) { if (!command.startsWith(TASK_PREFIX) && !command.startsWith(QL_PREFIX)) {
command = `${TASK_PREFIX}${tab.command}`; command = `${TASK_PREFIX}${tab.command}`;
} }
const crontab_job_string = `ID=${tab.id} ${command}`; let commandVariable = `ID=${tab.id} `
if (tab.task_before) {
commandVariable += `task_before='${tab.task_before.replace(/'/g, "'\\''")
.trim()}' `;
}
if (tab.task_after) {
commandVariable += `task_after='${tab.task_after.replace(/'/g, "'\\''")
.trim()}' `;
}
const crontab_job_string = `${commandVariable}${command}`;
return crontab_job_string; return crontab_job_string;
} }
@ -525,12 +521,12 @@ export default class CronService {
crontab_string += '# '; crontab_string += '# ';
crontab_string += tab.schedule; crontab_string += tab.schedule;
crontab_string += ' '; crontab_string += ' ';
crontab_string += this.make_command(tab); crontab_string += this.makeCommand(tab);
crontab_string += '\n'; crontab_string += '\n';
} else { } else {
crontab_string += tab.schedule; crontab_string += tab.schedule;
crontab_string += ' '; crontab_string += ' ';
crontab_string += this.make_command(tab); crontab_string += this.makeCommand(tab);
crontab_string += '\n'; crontab_string += '\n';
} }
}); });
@ -584,7 +580,7 @@ export default class CronService {
.map((doc) => ({ .map((doc) => ({
id: String(doc.id), id: String(doc.id),
schedule: doc.schedule!, schedule: doc.schedule!,
command: doc.command, command: this.makeCommand(doc),
extraSchedules: doc.extra_schedules || [] extraSchedules: doc.extra_schedules || []
})); }));
await cronClient.addCron(sixCron); await cronClient.addCron(sixCron);

View File

@ -94,7 +94,7 @@ env_str_to_array() {
## 正常运行单个脚本,$1传入参数 ## 正常运行单个脚本,$1传入参数
run_normal() { run_normal() {
local file_param=$1 local file_param=$1
if [[ $# -eq 1 ]] && [[ "$real_time" != "true" ]]; then if [[ $# -eq 1 ]] && [[ "$real_time" != "true" ]] && [[ "$no_delay" != "true" ]]; then
random_delay "$file_param" random_delay "$file_param"
fi fi

View File

@ -436,11 +436,23 @@ handle_task_before() {
[[ $is_macos -eq 0 ]] && check_server [[ $is_macos -eq 0 ]] && check_server
. $file_task_before "$@" . $file_task_before "$@"
if [[ $task_before ]]; then
echo -e "执行前置命令\n"
eval "$task_before"
echo -e "\n执行前置命令结束\n"
fi
} }
handle_task_after() { handle_task_after() {
. $file_task_after "$@" . $file_task_after "$@"
if [[ $task_after ]]; then
echo -e "\n执行后置命令\n"
eval "$task_after"
echo -e "\n执行后置命令结束"
fi
local etime=$(date "+$time_format") local etime=$(date "+$time_format")
local end_time=$(format_time "$time_format" "$etime") local end_time=$(format_time "$time_format" "$etime")
local end_timestamp=$(format_timestamp "$time_format" "$etime") local end_timestamp=$(format_timestamp "$time_format" "$etime")

View File

@ -456,5 +456,9 @@
"语言": "Language", "语言": "Language",
"中...": "ing...", "中...": "ing...",
"请选择操作符": "Please select operator", "请选择操作符": "Please select operator",
"新增定时规则": "New Timing Rules" "新增定时规则": "Add Timing Rules",
"运行任务前执行的命令,比如 cp/mv/python3 xxx.py/node xxx.js": "Run commands before executing the task, e.g., cp/mv/python3 xxx.py/node xxx.js",
"运行任务后执行的命令,比如 cp/mv/python3 xxx.py/node xxx.js": "Run commands after executing the task, e.g., cp/mv/python3 xxx.py/node xxx.js",
"请输入运行任务前要执行的命令": "Please enter the command to run before executing the task",
"请输入运行任务后要执行的命令": "Please enter the command to run after executing the task"
} }

View File

@ -456,5 +456,9 @@
"语言": "语言", "语言": "语言",
"中...": "中...", "中...": "中...",
"请选择操作符": "请选择操作符", "请选择操作符": "请选择操作符",
"新增定时规则": "新增定时规则" "新增定时规则": "新增定时规则",
"运行任务前执行的命令,比如 cp/mv/python3 xxx.py/node xxx.js": "运行任务前执行的命令,比如 cp/mv/python3 xxx.py/node xxx.js",
"运行任务后执行的命令,比如 cp/mv/python3 xxx.py/node xxx.js": "运行任务后执行的命令,比如 cp/mv/python3 xxx.py/node xxx.js",
"请输入运行任务前要执行的命令": "请输入运行任务前要执行的命令",
"请输入运行任务后要执行的命令": "请输入运行任务后要执行的命令"
} }

View File

@ -43,7 +43,6 @@ import { request } from '@/utils/http';
import CronModal, { CronLabelModal } from './modal'; import CronModal, { CronLabelModal } from './modal';
import CronLogModal from './logModal'; import CronLogModal from './logModal';
import CronDetailModal from './detail'; import CronDetailModal from './detail';
import cron_parser from 'cron-parser';
import { diffTime } from '@/utils/date'; import { diffTime } from '@/utils/date';
import { history, useOutletContext } from '@umijs/max'; import { history, useOutletContext } from '@umijs/max';
import './index.less'; import './index.less';

View File

@ -143,6 +143,32 @@ const CronModal = ({
<Form.Item name="labels" label={intl.get('标签')}> <Form.Item name="labels" label={intl.get('标签')}>
<EditableTagGroup /> <EditableTagGroup />
</Form.Item> </Form.Item>
<Form.Item
name="task_before"
label={intl.get('执行前')}
tooltip={intl.get(
'运行任务前执行的命令,比如 cp/mv/python3 xxx.py/node xxx.js',
)}
>
<Input.TextArea
rows={4}
autoSize={{ minRows: 1, maxRows: 5 }}
placeholder={intl.get('请输入运行任务前要执行的命令')}
/>
</Form.Item>
<Form.Item
name="task_after"
label={intl.get('执行后')}
tooltip={intl.get(
'运行任务后执行的命令,比如 cp/mv/python3 xxx.py/node xxx.js',
)}
>
<Input.TextArea
rows={4}
autoSize={{ minRows: 1, maxRows: 5 }}
placeholder={intl.get('请输入运行任务后要执行的命令')}
/>
</Form.Item>
</Form> </Form>
</Modal> </Modal>
); );