首先项目是通过node-schedule
包来实现定时任务功能的,如果想要通过数据库动态管理定时任务(添加任务、删除任务、变更任务执行时间),有什么好的思路和方法么?求各位大佬指导。
附上现在使用的代码:
// 定义任务列表
function startJob(code) {
switch (code) {
case '001':
// 任务执行文件
break;
default:
break;
}
}
// 每5分钟检查定时任务设置
schedule.scheduleJob('0 */5 * * * *', function () {
TimingTaskSwitchModel.find(
{
state: 'on',
status: 'normal'
},
function (e, models) {
if (e || !models) {
originalJobs.forEach(function (j) {
try {
schedule.cancelJob(j);
} catch (error) {
console.log(moment().format('YYYY-MM-DD HH:mm:ss.SSS') + ' 取消任务:', j, error);
}
});
}
openedJobs = [];
allJobs = [];
models.forEach(function (taskSwitch) {
time = null;
taskSwitch = taskSwitch.toObject();
if (taskSwitch['rule'] && typeof taskSwitch['rule'] === 'object') {
time = new schedule.RecurrenceRule();
(((taskSwitch['rule'] || {})['second'] || [])[0] || ((taskSwitch['rule'] || {})['second'] || [])[0] === 0) && (time['second'] = (taskSwitch['rule'] || {})['second']);
(((taskSwitch['rule'] || {})['minute'] || [])[0] || ((taskSwitch['rule'] || {})['minute'] || [])[0] === 0) && (time['minute'] = (taskSwitch['rule'] || {})['minute']);
(((taskSwitch['rule'] || {})['hour'] || [])[0] || ((taskSwitch['rule'] || {})['hour'] || [])[0] === 0) && (time['hour'] = (taskSwitch['rule'] || {})['hour']);
(((taskSwitch['rule'] || {})['dayOfWeek'] || [])[0] || ((taskSwitch['rule'] || {})['dayOfWeek'] || [])[0] === 0) && (time['dayOfWeek'] = (taskSwitch['rule'] || {})['dayOfWeek']);
} else if (!taskSwitch['rule'] && taskSwitch['date']) {
time = new Date(taskSwitch['date']);
}
if (time) {
openedJobs.push({
code: taskSwitch['code'],
time: time
});
allJobs.push(taskSwitch['code']);
}
});
executionJobs = openedJobs;
originalJobs.forEach(function (originalJob) {
if (allJobs.indexOf(originalJob) < 0) {
console.log(moment().format('YYYY-MM-DD HH:mm:ss.SSS') + ' 取消任务:' + originalJob);
if (schedule.scheduledJobs[originalJob]) {
schedule.cancelJob(originalJob);
}
delete jobTimes[originalJob];
}
});
originalJobs = allJobs;
}
);
});
// 设置定时任务(每5分执行一次)
schedule.scheduleJob('0 */5 * * * *', function () {
executionJobs.forEach(function (executionJob) {
if (String.trim(JSON.stringify(jobTimes[executionJob['code']])) !== String.trim(JSON.stringify(executionJob['time']))) {
console.log(moment().format('YYYY-MM-DD HH:mm:ss.SSS') + ' 任务变更:' + executionJob['code']);
jobTimes[executionJob['code']] = executionJob['time'];
if (schedule.scheduledJobs[executionJob['code']]) {
schedule.cancelJob(executionJob['code']);
}
schedule.scheduleJob(executionJob['code'], jobTimes[executionJob['code']], function () {
startJob(executionJob['code']);
});
}
});
});
我写了个电影cms是这样的,pm2守护电影系统的进程。单独写了一个cron.js,用于执行定时任务,使用另一个进程守护工具forever守护cron.js。动态的开启,关闭定时任务。app.js和cron.js通讯,使用http服务。
app.js监听的是9999端口,cron.js监听的是8888端口。app.js后台管理系统创建一个定时任务的时候,通过request或者axios发生一个post请求。那边cron.js收到http请求,创建删除的时候通过参数识别,比如创建createCron,删除removeCron。然后带上要输入的时间参数( )。就是这样实现的,只不过cron.js这样没有负载,是单线程。想高并发就得自己写一个并发模型。
首先解决的就是:nodejs定时任务通过pm2负载之后的一个问题就是,你无法关闭的定时任务,比如双核心四线程,那么pm2会启动四个nodejs,你发送的请求创建的时候可能分到A线程里面执行。但是第二次关闭的时候pm2可能会给你分发到B线程,但是B线程里面根本就没有执行定时任务,所以你无法关闭。
所以想要能找到这个任务,并且关闭,就必须单独出来。