Schedule crontab jobs in an AdonisJs app

After some weeks we started to migrate our Laravel apps to Node.js and we have chosen to use, as framework, AdonisJs, because of its similarity with Laravel.

It works great, but something's missing: the possibility to schedule a job to run it in a specific time, like the crontab and the "schedule" of Laravel.

You have two ways to achieve it:

  1. Edit the crontab of your server (crontab -e) and add something like 15 * * * * cd /var/www/your_project && adonis yourcommand >/dev/null 2>&1 (just an example);

  2. Use Adonis Scheduler, which is a third-party library (not official) but very useful.

The repository I linked is a fork of a fork. The original repo doesn't have the support for Adonis 4 (the latest version), so the user ntvsx193 updated it making it work with v4 and I created a "security" copy (forking its fork, yes).

Installation

Note: If you are using Adonis v3.x, please follow the original installation tutorial on the repository.

The first part of everything you do is the installation. Since its a node.js project, we use npm with this command: npm i --save git+https://github.com/danilopolani/adonis-scheduler.git. Note we used the syntax git+ because the updated version is not available on npm packages, so we link directly to the repository.

Now open your start/app.js file and...

1. Add adonis-scheduler/providers/SchedulerProvider to your providers array like this:

const providers = [
  ...
  'adonis-scheduler/providers/SchedulerProvider',
];

2. Create the alias:

const aliases = {
  ...
  Scheduler: 'Adonis/Addons/Scheduler',
};

3. Register the command:

const aceProviders = [
  ...
  'adonis-scheduler/providers/CommandsProvider',
];

Now let's write a task.

Tasks: schedule the world

The updates for our dear ntvsx193 include a command to generate a task; you need just to run adonis make:task ScheduleIt from your terminal and here you go. Note: The make:task command will strip the word "Task" from the name, so if you write "MyTask" it will create a file named only "My.js".

Open your generated file at app/Tasks/ScheduleIt.js and you'll see this structure:

'use strict'

const Task = use('Task');

class ScheduleIt extends Task {
  static get schedule() {
    return '0 */1 * * * *';
  }

  async handle() {
    this.info('Task ScheduleIt handle');
  }
}

module.exports = ScheduleIt;

In the schedule section, you have to put the crontab value. I suggest you to use the useful Crontab generator tool to know what to put in here.

For example, if I want to schedule my job at 3:15am of every day, so I choose the minute and the hour in the list at the right of each box, leaving Days, Months and Weekday set to "Every ...".

Write whatever you want under "Command to execute" and press Enter. It will print the complete line to copy-paste, for example 15 3 * * * foo >/dev/null 2>&1, where 'foo' is my fake command. We need to retrieve only the part with the asterisks: 15 3 * * *.

Putting it in the schedule function, it becomes this:

static get schedule() {
  return '15 3 * * *';
}

Since we need to test if it's working, we use it as "schedule time" every minute: * * * * *.

In the handle section, you'll put your real code. Since it's an async method, you can use as well the await functionality of ES6.

In this tutorial, we leave the this.info helper to print in our terminal, every minute, the phrase Task ScheduleIt handle.

Run the scheduler

The repository tells us only to run the command adonis run:scheduler, but of course, in our server we can't run it from the terminal, but we need something to keep it alive.

I have found three ways for this:

  1. Use pm2, the "equivalent" of supervisor for node.js processes.

  2. Use supervisor to keep the process alive.

  3. Include the schedule runner in your project.

After thinking about them, I realized that the last one is the more simple to adopt: with pm2 you need to create a new process and save it (to preserve it when you reboot your server); with supervisor you need to create a config file for the process, reread and update.

With the last option you just need to copy and paste a code in a file. Simple, isn't it?

Open the file start/kernel.js and right after the line const Server = use ('Server'), put this:

/*
|--------------------------------------------------------------------------
| Run Scheduler
|--------------------------------------------------------------------------
|
| Run the scheduler on boot of the web sever.
|
*/
const Scheduler = use('Adonis/Addons/Scheduler');
Scheduler.run();

Now we are ready to test it.

Test

Run the app like always, with adonis serve --dev and wait one minute to see the first message.

After two minutes, your terminal will look like the screenshot below.