Do you wish to automate certain tasks on your application server and free yourself from the burden of manual execution? Are you looking to avoid the hassle of remembering to periodically manage data transfer or cleanup on different parts of the server?
Enter cron job schedulers, a widely adopted solution for automating such tasks.
Cron job scheduling has become a standard practice in modern applications. Essentially, cron acts as a daemon, which means it runs continuously in the background, awaiting its scheduled tasks. Just like a web server, which remains idle until it receives a request for a web page, cron stays dormant until it's time to execute the specified jobs.
In this article, we will explore how to schedule cron jobs in various Node.js applications using the node-cron
library. node-cron is a node module accessible through npm.
To set up job scheduling with node-cron, we'll make use of the cron.schedule()
method.
The signature of the cron.schedule()
method looks like:
cron.schedule(expression, function, options);
Let’s explore each of the arguments.
The cron expression is the first argument in the cron.schedule() method. It plays a crucial role in defining the schedule for executing a cron job. This is called a crontab expression, named after the crontab command-line tool, which allows scheduling multiple jobs within a single crontab file.
Comprising six elements separated by spaces, the cron expression provides a structured way to define the schedule. Here's a concise reference guide explaining the significance of each element:
We can replace each asterisk with one of the following characters so that the expression describes the time we want the job to be executed:
*: An asterisk means every interval. Eg:- If the asterisk symbol is in the month field, it means the task is run every month.
,: The comma allows us to specify a list of values for repetition. Eg:- If we have 1, 3, and 5 in the month field, the task will run in months 1, 3, and 5 (January, March, and May).
-: The hyphen allows us to specify a range of values. If we have 1-5 in the day-of-the-week field, the task will run every weekday (Monday to Friday).
/: The slash allows us to specify expressions like every xth interval. If we have */4 in the hour field, the action will be performed every 4 hours.
The seconds element can be left out. In this case, the cron expression will only consist of 5 elements and the first element describes the minutes and not the seconds.
If unsure about manually writing cron ex[ressions, we can use free tools like Crontab Generator or Crontab.guru to generate a cron expression.
As the second argument of the cron.schedule() method, the cron function holds the code that executes whenever the associated cron expression is triggered.
Within this function, we have the freedom to implement various actions according to our requirements. Whether it involves sending emails, creating database backups, or downloading data, we can perform any desired tasks. The possibilities are vast, allowing us to automate and streamline diverse processes based on our needs.
In the third argument of the cron.schedule() method we can provide some options. This argument is optional.
Here is an example of what a cron options object looks like.
{
scheduled: false,
timezone: "Asia/Kolkata"
}
The scheduled option here is a boolean to indicate whether the job is enabled or not (default is true).
With the timezone option, we can define the timezone in which the cron expression should be evaluated.
I will now discuss a small example with you, where I scheduled a simple chron in my recent Express app.
You can read more about this app here.
As discussed in the logout section that in case of automatic logouts because of token expiry we will schedule a chron to remove expired tokens from the database. So I scheduled a chron job that executes every 6 AM, iterates in the users' table from my database, checks for expired tokens and deletes the corresponding session details.
cron.schedule("0 6 * * *", async function () {
const users = await User.find().exec();
users.forEach(async (userDetails) => {
if (userDetails?.sessionsDetails.length > 0) {
const updatedSessionDetails = await User.filterExpiredSessions(
userDetails?.sessionsDetails
);
if (updatedSessionDetails.length < userDetails.sessionsDetails.length) {
await User.updateOne(
{
_id: userDetails._id,
},
{ sessionsDetails: updatedSessionDetails }
);
}
}
});
});
// code for filterExpiredSessions
userSchema.statics.filterExpiredSessions = async function (
sessionDetails: TokenDetails[]
) {
let updatedSessionDetails: {
expired?: boolean;
token: string;
sessionDetails: parser.IResult;
}[] = [...sessionDetails].map((session) => ({
...session,
expired: false,
}));
updatedSessionDetails.forEach((session) => {
try {
jwt.verify(session.token, process.env.JWT_SECRET || "") as JwtPayload;
} catch (error) {
session.expired = true;
}
});
updatedSessionDetails = updatedSessionDetails
.filter((session) => !session.expired)
.map((session) => {
delete session["expired"];
return session;
});
return updatedSessionDetails;
};
0 6 * * *
:- This means that chron executes at 6 A.M. every morning, runs through all our users and filters any expired token sessions present in the database. This is how we would handle automatic logouts using chron.
In this article, we illustrated the process of scheduling tasks on a Node.js server using the node-cron schedule method. This method enables the automation and scheduling of repetitive or future tasks, making it applicable to both existing and upcoming projects.
It's important to note that apart from node-cron, there are other job scheduler tools available for Node.js applications, such as node-schedule, Agenda, Bree, Cron, and Bull. We should always evaluate each of them carefully to determine the best fit for our particular project's requirements.
Docker: Managing data with Volumes (Part 2) Hello everyone, In the last post, we discussed the concept of volumes. We discussed the use of named and anonymous volumes. In this post, we will discuss the need and use of bind mounts We will learn the use of .dockerignore files. We will also see working with environment variables and .env files. We will also learn the use of build arguments.
Docker: Managing data with Volumes (Part 1) Hello everyone, In the last post, we learned to perform various operations with containers and images. In this post, we will explore volumes, which are like state management for running applications with docker. We will discuss different kinds of data we encounter while working with docker. We will learn about different kinds of volumes, and explore anonymous and named volumes in detail by discussing their implementation in a node server application. We will create these volumes in our system.