Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Start/stop cronjob on button click in Nodejs Express app

I have been working on a project which requires the start and stop of cron scheduler when a user clicks on a button on the front end. Basically when a user clicks on a button, the cron job will start. And clicking the stop button will stop the timer. It is as simple as that.

To achieve that, I am making post requests to the Nodejs/Express backend on button click which triggers start/stop function of the scheduler. This is how the endpoint looks like:

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)
    }
});

Right now the scheduler runs perfectly but it doesn't stop on second button click. It keeps on running. I feel like I'm not calling task.start() and task.stop() at correct places where it would work. And I don't know where the correct places are. I'm actually new to cronjobs.

It would be great if someone tells me what I am doing wrong.

Thanks in advance.

like image 711
Zak Avatar asked Apr 07 '21 13:04

Zak


2 Answers

Every time you hit the scheduler api a new instance of cron-job is made and you are stopping the newly defined instance of cron-job not the previous one.

Solution is to define the cron-job out of the scope of router so that whenever you hit the scheduler api the instance won't change

Like this:

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)
    }
});
like image 176
Abhishek Pankar Avatar answered Oct 23 '22 07:10

Abhishek Pankar


The problem might come from the line:

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

which, actually, creates a new task and uses a new Scheduler if you read the source code of 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;
    }

(which, internally, uses: 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);

So, when you call:

    task.stop();

As far as I understand, what you do is calling the method "stop" of a brand new task, not the method stop of the task you launched the first time you clicked the button.

Judging by your code, the problem is that you are not actually using your scheduler while using the task.

PS: The module also exposes a function that lets you retrieve tasks from its storage: https://github.com/node-cron/node-cron/blob/fbc403930ab3165ffef7d53387a29af92670dfea/src/node-cron.js#L58

But as I haven't found any documentation about it, I do not recommend using it.

like image 1
Ribodou Avatar answered Oct 23 '22 07:10

Ribodou