node定时发送消息提醒

420 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

定时器 node-schedule 邮件服务 nodemailer

初级 每有一个用户提交一个请求就开启一个重复任务 弊端:不方便在运行时停止任务 需要获取job实例执行job.cancel()方法,不利于数据库增删改查 改良: 只有一个负责定时发送任务的计时器 在规定时间从数据库中获取满足条件的信息进行提醒。这样数据库增删就可以实现任务是否发送以及赞死停止提醒活更改提醒时间等功能

初级

/**
 * @description: 定时重复任务
 * @param {string} content 任务内容
 * @param {string} interval 时间间隔
 */
// 晚10-早7不执行
const startHour = 7;
const endHour = 22;
const timeTask = (sendMail, insertOne) => async (req, res) => {
    let { content, interval, mail } = req.payload;
    console.log(`每隔 ${interval}小时提醒${mail} ${content}`);
    interval = Number(interval);// 0.5 1 2 3 ...
    //创建重复规则
    const rule = new schedule.RecurrenceRule();
    rule.hour = [];//早7-晚10执行
    rule.minute = 0;
    rule.second = 0;

    const payloadHours = endHour - startHour;//共有多少个小时有效执行任务
    //半小时
    if (interval < 1) {
        rule.minute = [33, 59];
        rule.hour.push(startHour);
        interval = 1;//为了下面添加每个小时方便处理 将interval置为1
    };

    for (let i = 1; i < (payloadHours) / interval; i++) {
        rule.hour.push(startHour + i * interval);
    }

    console.log("重复规则:", rule);
    const job = schedule.scheduleJob(rule, async () => {
        console.log("执行一次 - 当前时间:" + new Date().toLocaleString() + '任务:' + content);
        const info = await sendMail({
            message: content, mail,
            subject: 'hello', from: "定时提醒 <2218176087@qq.com>"
        });
        console.log('定时发送:', info);
    });
   res.json({ message: '设置成功' })
}

改良

与mongodb配合 增加 增删改查 对应请求 半个小时获取一次满足条件的数据进行提醒


/**
 * @description: 向数据库中添加一条定时任务记录
 * @param {string} content 任务内容
 * @param {string} interval 时间间隔
 * @param {mail} mail 提醒邮箱
 */
const createTimeTask = (insertOne) => async (req, res) => {
    console.log(`每隔 ${req.payload.interval}小时提醒${req.payload.mail} ${req.payload.content}`);
    console.log(req.payload);
    const result = await insertOne(timeTaskCollection, req.payload);
    if (result) res.json({ message: '创建任务成功' });
}

/**
 * @description: 删除数据库中的任务记录
 * @param {string} taskId _id 
 */
const deleteTimeTask = (deleteOne) => async (req, res) => {
    const result = await deleteOne(timeTaskCollection, res.payload.id);
    if (result) res.json({ message: '删除成功' });
}

/**
 * @description: 查询数据库中绑定在某邮箱上的任务记录
 * @param {mail} mail 
 */
const queryTimeTaskByMail = (findData) => async (req, res) => {
    const list = await findData({ collection: timeTaskCollection, find: { mail: req.payload.mail } });
    if (list) res.json({ message: '查询成功', list });
}

// 晚10-早7不执行
const startHour = 7;
const endHour = 22;
const payloadHours = endHour - startHour;// 15 共有多少个小时有效执行任务

/**
 * @description: 定时重复任务
 * @param {string} content 任务内容
 * @param {string} interval 时间间隔
 * @param {mail} mail 提醒邮箱
 */
const startTimeTask = async (findData, sendMail) => {
    //创建重复规则
    const rule = new schedule.RecurrenceRule();
    rule.hour = [];//早7-晚10执行  [7,8,9,10 ... 21]
    rule.minute = [0, 30];
    rule.second = 0;

    let i = 0;
    while (i < payloadHours) {
        rule.hour.push(startHour + i);
        i++;
    }
    //查询满足条件并发送
    const repeat = async () => {
        const data = new Date();
        const hours = data.getHours();
        const minutes = data.getMinutes();// 0  /  30

        //开始小时不执行 例如 7点开始则 7点整不执行 7点半执行
        if (hours === startHour && !minutes) return;

        const interval = ["0.5"];//每隔半个小时执行 所以半小时任务一定符合

        const diffHour = hours - startHour;

        if (diffHour) {//找到能被整除的数
            // '<' 目的是少比较一次,自己肯定能被整除啦
            for (let i = 1; i < diffHour; i++) {
                if (diffHour % i === 0) interval.push(i.toString());
            }
            interval.push(diffHour.toString());
        }

        const list = await findData({
            collection: timeTaskCollection,
            find: { interval: { $in: interval } }
        });
        console.log({ interval, list });
        list.forEach(({ mail, content }) => {
            console.log(`提醒${mail} ${content} --${data.toLocaleString()}任务 `);
            sendMail({
                message: content, mail,
                subject: content, from: "定时提醒 <2218176087@qq.com>"
            });
        });
    }

    schedule.scheduleJob(rule, repeat);
}

体验地址 hongbin.xyz/timeTask