Create simple interval tasks in node.js

We can take advantage of setTimeout in JavaScript to build task runners in Node. This will not scale well but if all you need is something simple to get your tasks running the following example will work for you.

Lets create a task runner that runs once at the top of every hour, we'll call it every-hour.js and put it in a /schedules directory at the root of our project.

javascript
// My node app
const mySchedule = require('/schedules/every-hour');

// etc...
mySchedule();

We run it when we start our node application.

In order to ensure that it correctly runs at the top of every hour we'll need to perform a calculation inside of that file.

javascript
function generateTimeout () {
    const time = new Date();
    const toth = new Date(time.getFullYear(), time.getMonth(), time.getDate(), time.getHours() + 1, 0, 0, 0);
    const ms = toth - time;
    console.log('Top of the hour after n minutes', ms / 1000 / 60);
    setTimeout(() => { everyHour(); }, ms);
}

module.exports = generateTimeout;

Unfortunately JavaScript's built-in Date functionality is not particularly intuitive. You see from the above code we are calculating a number of milliseconds between the current time and the point of time it will be when we want our code to run.

When the application starts, you will see a message in the console that says something like. "Top of the hour after n minutes 1.2252666666666667"

A harder example, if we want something like this to run every 15 minutes. It will be necessary to calculate when the next quarter of an hour passes. This doesn't come built in to the Date instance and so we will need to calculate it manually.

javascript
const getMinutes = (time) => {
    let minutes = time.getMinutes();
    do { minutes++; } while (minutes % 15 !== 0);
    return minutes;
};

function generateTimeout () {
    const time = new Date();
    const qoah = new Date(time.getFullYear(), time.getMonth(), time.getDate(), time.getHours(), getMinutes(time), 0, 0);
    const ms = qoah - time;
    console.log('Quarter of an hour after n minutes', ms / 1000 / 60);
    setTimeout(() => { everyFifteenMinutes(); }, ms);
}

module.exports = generateTimeout;

As you can see it is still much the same we just want to know when the next closest 15 minute interval occurs. In order to have this run continuously at an interval we call the method again.

javascript
const everyHour = async () => {
    // my scheduled code
    await doMyThing();

    generateTimeout();
};

It doesn't matter how long it takes your code to finish as the next time it runs will always be recalculated correctly. Not the ideal solution when you are considering scale and running multiple nodes, however to get your app off the ground it's a simple mechanism that's easy to write and use.