Scheduling Tasks with Ease: A Node.js Tutorial
The Need for a Job Scheduler
When building an application, recurring tasks and reminders are essential. From sending billing information to performing database backups, these tasks can be crucial to your app’s success. But how do you ensure they’re executed efficiently and reliably?
Using JavaScript’s built-in methods, such as setTimeout
and setInterval
, may seem like a simple solution. However, these methods don’t scale horizontally and lack the ability to track completed or aborted jobs. This is where a job scheduler comes in.
Introducing Agenda.js
Agenda.js is a popular Node.js scheduler that stands out from the crowd. By using MongoDB for persistence, Agenda.js offers less configuration compared to Redis-based schedulers. Its lightweight and robust feature set make it an ideal choice for your application.
Setting Up Agenda.js
To get started with Agenda.js, you’ll need to initialize a singleton instance and define your tasks. Agenda.js provides three essential methods:
- agenda.every: Repeats a task at a specified interval
- agenda.schedule: Schedules a task to run once at a specific time
- agenda.now: Schedules a task to run immediately
const agenda = require('agenda');
agenda.every('1 minute', 'end-emails'); // Repeat task every 1 minute
agenda.schedule('2019-02-13 14:30:00', 'end-notifications'); // Schedule task to run once at a specific time
agenda.now('process-data'); // Schedule task to run immediately
Structuring Your Code
To integrate Agenda.js into your Express application, create a singleton instance and define your tasks using closures. Organize your code into separate files for definitions, handlers, and schedulers.
// tasks/definitions/mail.js
module.exports = {
type: 'ail',
handler: async () => {
// Send emails logic here
}
};
// tasks/handlers/mailHandler.js
const mailDefinition = require('./definitions/mail');
module.exports = async () => {
await mailDefinition.handler();
};
// tasks/schedulers/agenda.js
const agenda = require('agenda');
const mailHandler = require('./handlers/mailHandler');
agenda.define('send-emails', mailHandler);
agenda.every('1 minute', 'end-emails');
Defining Tasks
Create separate files for each task definition, such as mail definitions and payout definitions. Each definition should include a handler function that performs the required task.
Using Agenda.js in Controllers
Once you’ve set up Agenda.js, you can use it in your controllers or routes. To keep things organized, consider wrapping Agenda.js in another module.
// controllers/mailController.js
const agenda = require('../tasks/schedulers/agenda');
exports.sendEmails = async () => {
await agenda.now('send-emails');
};
Avoiding the Single Responsibility Principle
To prevent controllers from becoming too bloated, use an event emitter to dispatch events that can be reacted to. This approach keeps your code organized and scalable.
// eventEmitter.js
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('send-emails', async () => {
// Handle send-emails event here
});
// controllers/mailController.js
const myEmitter = require('../eventEmitter');
exports.sendEmails = async () => {
myEmitter.emit('send-emails');
};
Putting it All Together
By following this tutorial, you’ll be able to handle cron jobs in a structured manner using Agenda.js. Remember to explore the extensive documentation for Agenda.js and the event emitter library for more advanced use cases.
Monitoring Your Application
To ensure your Node.js application runs smoothly, consider using a monitoring tool that records everything that happens while a user interacts with your app, helping you identify and fix issues quickly.