【问题标题】:Start/stop cronjob on button click in Nodejs Express app在 Nodejs Express 应用程序中单击按钮时启动/停止 cronjob
【发布时间】:2021-07-03 08:10:06
【问题描述】:

我一直在做一个项目,当用户单击前端的按钮时,它需要启动和停止 cron 调度程序。基本上,当用户单击按钮时,cron 作业将启动。单击停止按钮将停止计时器。就这么简单。

为了实现这一点,我在单击按钮时向 Nodejs/Express 后端发出发布请求,这会触发调度程序的启动/停止功能。这是端点的样子:

const cron = require('node-cron');

router.post('/scheduler', async (req, res) => {

    // gets the id from the button
    const id = req.body.id;

    try{
         // finds the scheduler data from the MongoDB
         const scheduler = await Scheduler.find({ _id: id });

         // checks whether there is a scheduler or not
         if ( !scheduler  ) {
             return res.json({
                  error: 'No scheduler found.'
             });
         }

         // creates the cronjob instance with startScheduler 
         const task = cron.schedule('*/10 * * * * *', () =>  {
              console.log('test cronjob running every 10secs');
         }, {
              scheduled: false
         });

         // checks if the scheduler is already running or not. If it is then it stops the scheduler
         if ( scheduler.isRunning ) {

             // scheduler stopped
             task.stop();

             return res.json({
                  message: 'Scheduler stopped!'
             });
         }

         // starts the scheduler
         task.start();

         res.json({
              message: 'Scheduler started!'
         });

    }catch(e) {
         console.log(e)
    }
});

现在调度程序运行良好,但不会在第二次单击按钮时停止。它继续运行。我觉得我没有在正确的地方打电话给task.start()task.stop()。而且我不知道正确的地方在哪里。我实际上是 cronjobs 的新手。

如果有人告诉我我做错了什么,那就太好了。

提前致谢。

【问题讨论】:

    标签: javascript node.js express cron scheduler


    【解决方案1】:

    每次您点击scheduler api 时,都会创建一个cron-job 的新实例,并且您正在停止新定义的cron-job 实例 而不是上一个

    解决方案是定义 cron-job 超出路由器范围,这样每当您点击scheduler api 时,实例都不会改变

    像这样:

    const cron = require('node-cron');
    
    // creates the cronjob instance with startScheduler 
    const task = cron.schedule('*/10 * * * * *', () =>  {
        console.log('test cronjob running every 10secs');
    }, {
        scheduled: false
    });
    
    router.post('/scheduler', async (req, res) => {
    
        // gets the id from the button
        const id = req.body.id;
    
        try{
             // finds the scheduler data from the MongoDB
             const scheduler = await Scheduler.find({ _id: id });
    
             // checks whether there is a scheduler or not
             if ( !scheduler  ) {
                 return res.json({
                      error: 'No scheduler found.'
                 });
             }
    
             // checks if the scheduler is already running or not. If it is then it stops the scheduler
             if ( scheduler.isRunning ) {
    
                 // scheduler stopped
                 task.stop();
    
                 return res.json({
                      message: 'Scheduler stopped!'
                 });
             }
    
             // starts the scheduler
             task.start();
    
             res.json({
                  message: 'Scheduler started!'
             });
    
        }catch(e) {
             console.log(e)
        }
    });
    

    【讨论】:

    • 嘿伙计。你知道我们是否可以创建多个可以通过它们的 ID 停止的 cron 作业吗?例如,我启动了 cron 作业 1 和 2,现在我只想停止 cron 作业 2。我怎样才能只停止那个 cron 作业?
    • 定义另一个超出范围的 cronjob,就像 Abhishek 为第一个 cronjob 建议的那样。
    • 另外不要忘记在每次启动/停止后更新您的数据库中的调度程序运行状态
    • @Zak 这就是声明 'const task' 的用途,控制 cronjob 实例。因此,您将复制声明,但将第 2、3、4 个 cronjob 变量命名为“const task2、const task3、const task4”(或者更好的是,适当命名它们,即如果分配给 task2 的 cronjob 是“发送一些电子邮件” ,你应该把它命名为'const emailCron'。然后你可以通过对emailCron的引用来操作那个特定的对象,即:emailCron.stop();或emailCron.starat();hth!
    • @RobLittle 非常感谢。我现在明白了!
    【解决方案2】:

    问题可能出在下面一行:

        const task = cron.schedule('*/10 * * * * *', () =>  {
    

    实际上,如果您阅读 node-cron 的源代码,它会创建一个新任务并使用新的调度程序https://github.com/node-cron/node-cron/blob/fbc403930ab3165ffef7d53387a29af92670dfea/src/node-cron.js#L29

        function schedule(expression, func, options) {
            let task = createTask(expression, func, options);
            storage.save(task);
            return task;
        }
    

    (内部使用:https://github.com/node-cron/node-cron/blob/fbc403930ab3165ffef7d53387a29af92670dfea/src/scheduled-task.js#L7:

        let task = new Task(func);
        let scheduler = new Scheduler(cronExpression, options.timezone, options.recoverMissedExecutions);
    

    所以,当你打电话时:

        task.stop();
    

    据我了解,您所做的是调用全新任务的方法“停止”,而不是您第一次单击按钮时启动的任务的方法停止。

    从您的代码来看,问题在于您在使用任务时实际上并没有使用调度程序。

    PS: 该模块还公开了一个函数,可让您从其存储中检索任务:https://github.com/node-cron/node-cron/blob/fbc403930ab3165ffef7d53387a29af92670dfea/src/node-cron.js#L58

    但由于我没有找到任何关于它的文档,我不建议使用它。

    【讨论】:

    • 嘿,谢谢你的时间。所以它有点令人困惑,因为我的模型也被命名为调度程序。哈哈。但是我从您的回答中了解到的是,第二次按钮单击实际上会创建另一个任务,而不是停止前一个任务。所以我认为我可以在这里做两件事:1: put that task variable somewhere where it won't create the second time.2: call getTask() function but there's no documentation on it. 我认为我应该选择 1。你知道如何在整个设置中实现这一点吗?
    猜你喜欢
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多