Schedule background tasks in Node.js with node-cron

Photo by Sonja Langford / Unsplash

Most back-end web applications are built to serve client request synchronously: the client sends a request, the server receives the request, process it, and send the response to the client.

For some use cases, the process can be asynchronous, meaning we don't the back end doesn't need to wait for execution to complete before sending a response to the client. Usually,  there is a system to notify the client when the execution is done.

Some applications must execute background tasks periodically at a specific time or date. These kinds of tasks are also called Cron Jobs.

Use cases

The are many cases where you might need to run a Cron job; here are some examples:

  • Back up the database every Sunday at 2:00am
  • Delete older application logs on the disk every week
  • Send an email to users about their pricing plan expiration
  • Update the status of an account after a specific month
  • etc...

Cron syntax

The two main properties of a cron job are:

  • The task to execute
  • The time and the frequency at which this task will be executed

To define the time and the frequency of a cron job, we use the following cron expression * * * * * . The illustration below shows the meaning of each *

 ┌────────────── second (0 - 59) (optional)
 │ ┌──────────── minute (0 - 59) 
 │ │ ┌────────── hour (0 - 23)
 │ │ │ ┌──────── day of the month (1 - 31)
 │ │ │ │ ┌────── month (1 - 12)
 │ │ │ │ │ ┌──── day of the week (0 - 6) (0 and 7 both represent Sunday)
 │ │ │ │ │ │
 │ │ │ │ │ │
 * * * * * * 

Let's say we want to run a task every day at 2:30 pm; the cron expression will be: * 30 2 * * *  

To run a task at 10:15 am between Monday and Friday, the cron expression will be: 0 15 10 * * MON-FRI

This website can help you to write and validate your cron expression; it is straightforward and provides great detail about your cron expression.

Crontab.guru - The cron schedule expression editor
An easy to use editor for crontab schedules.

Set up the project

I created a minimal starter project for Node.js and Typescript; I wrote a blog post about it. Let's clone the project from GitHub and run it locally:


git clone https://github.com/tericcabrel/node-ts-starter.git node-cron-job

cd node-cron-job

yarn install

yarn start

We get the following output:

Set up and run the project locally.

Install node-cron

There are many Node.js packages for creating Cron jobs; we will use node-cron, so let's install it from NPM:


yarn add node-cron
yarn add -D @types/node-cron

We also installed the package @types/cron that provides the TypeScript types definition for node-cron.

Schedule a simple task

node-cron offers a simple API to schedule a task. To create a task that runs every minute, replace the content of the file scr/index.ts with the code below:


import cron from 'node-cron';

cron.schedule('* * * * *', () => {
  const date = new Date();

  console.log(`This task is running every minute - ${date.getHours()}:${date.getMinutes()}`);
});

We get the following output:

The scheduled task is running in the background every minute.

node-cron schedule options

When scheduling a new task, you can provide four options:

  • Name: the name of your scheduled task.
  • Scheduled: it's a boolean value indicating whether the cron job is running. It's true by default, so the cron job immediately starts when you run your application.
  • Timezone: it allows you to specify the timezone for the job scheduling. The possible values can be found on this page.
  • recoverMissedExecutions: specifies whether to recover missed executions instead of skipping them.

The cron job for the simple task above with the options look like this:


import cron from 'node-cron';

cron.schedule(
  '* * * * *',
  () => {
    const date = new Date();

    console.log(`This task is running every minute - ${date.getHours()}:${date.getMinutes()}`);
  },
  {
    scheduled: true,
    timezone: 'Europe/Paris',
    name: 'simple-task',
    recoverMissedExecutions: false,
  },
);

Manually schedule tasks

With the option scheduled set to false, the scheduled task is not running, and you must call the function start() to run the task scheduler. This is great if you need to run or pause a scheduled task.

Let's say our application sends an email address usage report every Monday at 7:30am. For some reason, we might want to pause and resume it.

We will create two API routes /start-scheduler and /stop-scheduler respectively for starting and stopping the scheduler.

To quickly generate API routes, we will install Express, which makes it easier to build Node REST API.

Create a REST API with Node.js, Express, MongoDB and Typescript
In this post, we will build a REST API for a user management application in Node.js and Typescript. Connect to a MongoDB database and store the data.

Run the command below to add Express and his types definition.


yarn add express
yarn add -D @types/express

Create a file src/scheduler.ts and add the code below:


import cron, { ScheduleOptions } from 'node-cron';

const scheduleOptions: ScheduleOptions = {
  scheduled: false,
  timezone: 'Europe/Paris',
  name: 'simple-task',
  recoverMissedExecutions: true,
};

const scheduleAction = async () => {
  const currentDate = new Date();

  console.log(`Build and send the weekly report - ${currentDate.getHours()}:${currentDate.getMinutes()}`);
  
  // Build and send the weekly report
};

const weeklyReportScheduler = cron.schedule('30 7 * * MON', scheduleAction, scheduleOptions);

export { weeklyReportScheduler };

Now replace the content of the file src/index.ts with code below:


import express from 'express';
import { weeklyReportScheduler } from './scheduler';

const PORT = 4500;

const app = express();

app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.post('/start-scheduler', async (req, res) => {
  await weeklyReportScheduler.start();

  return res.json({ message: 'OK' });
});

app.post('/stop-scheduler', async (req, res) => {
  await weeklyReportScheduler.stop();

  return res.json({ message: 'OK' });
});

app.listen(PORT, () => {
  console.log(`Application started on URL http://localhost:${PORT} 🎉`);
});

Run the command yarn start and open an HTTP client like Postman to send POST requests to start and stop the scheduler.

Now you can manually control your task scheduler.

Wrap up

node-cron provides a simple API to create scheduled background tasks from your Node.js application.

You can find the code source on the GitHub repository.

Follow me on Twitter or subscribe to my newsletter to avoid missing the upcoming posts and the tips and tricks I occasionally share.