DEV Community

Mohin Sheikh
Mohin Sheikh

Posted on

Cron Jobs in Node.js: A Complete Guide for Backend Developers

Table of Contents

  1. What Are Cron Jobs in Node.js?
  2. Approaches to Cron Jobs in Node.js
  3. Using System-Level Cron Jobs
  4. Using node-cron npm Package
  5. Advanced: Job Scheduling with agenda
  6. Common Use Cases
  7. Troubleshooting
  8. Best Practices

1. What Are Cron Jobs in Node.js?

Cron jobs let you execute functions or scripts at specific intervals (e.g., every minute, hourly, daily). In Node.js, you can:

  • Use system-level cron (via crontab).
  • Use in-process schedulers (npm packages like node-cron or agenda).

2. Approaches to Cron Jobs in Node.js

Method Pros Cons
System Cron Simple, OS-managed, survives app crashes Requires shell access, harder to debug
node-cron Easy in-app scheduling, JS syntax Tied to app lifecycle (stops if app crashes)
agenda Persistent jobs, retries, MongoDB support Requires MongoDB, more complex setup

3. Using System-Level Cron Jobs

Step 1: Create a Node.js Script

// scripts/cleanup.js
console.log('Cleaning up database at', new Date().toISOString());
// Add your logic here
Enter fullscreen mode Exit fullscreen mode

Step 2: Make the Script Executable

chmod +x scripts/cleanup.js
Enter fullscreen mode Exit fullscreen mode

Step 3: Schedule with Crontab

Edit your crontab:

crontab -e
Enter fullscreen mode Exit fullscreen mode

Add a job (use the full path to Node.js and your script):

# Run every day at 2:30 AM
30 2 * * * /usr/local/bin/node /home/user/app/scripts/cleanup.js >> /var/log/cron.log 2>&1
Enter fullscreen mode Exit fullscreen mode

Key Notes:

  • Find your Node.js path with which node (e.g., /usr/local/bin/node).
  • Use absolute paths for scripts and output files.
  • Log output to debug issues (>> /var/log/cron.log 2>&1).

4. Using node-cron npm Package

Ideal for in-app scheduling without relying on system cron.

Installation

npm install node-cron
Enter fullscreen mode Exit fullscreen mode

Basic Usage

const cron = require('node-cron');

// Run every minute
cron.schedule('* * * * *', () => {
  console.log('Running task every minute:', new Date().toISOString());
});
Enter fullscreen mode Exit fullscreen mode

Advanced Example (with Timezone)

const cron = require('node-cron');

// Run daily at 8:00 AM in Europe/London timezone
cron.schedule('0 8 * * *', () => {
  console.log('Sending morning report...');
}, {
  scheduled: true,
  timezone: 'Europe/London'
});
Enter fullscreen mode Exit fullscreen mode

Schedule Syntax Cheatsheet

Pattern Description
*/5 * * * * Every 5 minutes
0 9 * * 1-5 Weekdays at 9:00 AM
0 0 1 * * First day of the month at midnight

5. Advanced: Job Scheduling with agenda

For persistent, retriable jobs (requires MongoDB).

Installation

npm install agenda
Enter fullscreen mode Exit fullscreen mode

Setup

const Agenda = require('agenda');
const agenda = new Agenda({ db: { address: 'mongodb://localhost:27017/agenda' } });

// Define a job
agenda.define('send-email', async (job) => {
  const { userId } = job.attrs.data;
  console.log(`Sending email to user ${userId}`);
  // Add your email logic here
});

// Schedule job to run every 2 hours
agenda.every('2 hours', 'send-email', { userId: 123 });

// Start agenda
(async () => {
  await agenda.start();
})();
Enter fullscreen mode Exit fullscreen mode

Key Features:

  • Persistent jobs: Survive app restarts.
  • Retries: Automatically retry failed jobs.
  • Flexible scheduling: Use cron syntax or human-readable intervals.

6. Common Use Cases

1. Database Cleanup (Expired Tokens)

// Using node-cron
cron.schedule('0 0 * * *', async () => {
  await Token.deleteMany({ expiresAt: { $lt: new Date() } });
});
Enter fullscreen mode Exit fullscreen mode

2. Send Daily Reports via Email

// Using agenda
agenda.define('daily-report', async () => {
  const users = await User.find({ wantsReport: true });
  users.forEach(user => sendEmail(user.email, 'Your daily report!'));
});

agenda.every('0 9 * * *', 'daily-report');
Enter fullscreen mode Exit fullscreen mode

3. Cache Invalidation

// Every 10 minutes
cron.schedule('*/10 * * * *', () => {
  cache.clearExpired();
});
Enter fullscreen mode Exit fullscreen mode

4. Poll External APIs

// Poll every 5 minutes
cron.schedule('*/5 * * * *', async () => {
  const data = await fetch('https://api.example.com/data');
  await processData(data);
});
Enter fullscreen mode Exit fullscreen mode

7. Troubleshooting

Common Issues & Fixes:

  1. Cron job not running:

    • Check if the Node process is running (for node-cron/agenda).
    • For system cron, check logs: grep CRON /var/log/syslog.
  2. Module not found:

    • Use absolute paths in scripts.
    • Install dependencies globally if needed (not recommended).
  3. Permissions issues:

    • Ensure the cron user has execute access: chmod +x your-script.js.
  4. Timezone mismatches:

    • Use the timezone option in node-cron or set TZ in your OS.

Debugging Tips:

  • Log everything:
  cron.schedule('* * * * *', () => {
    console.log('Cron job started at', new Date());
    try {
      // Your logic here
    } catch (err) {
      console.error('Cron job failed:', err);
    }
  });
Enter fullscreen mode Exit fullscreen mode
  • Test with shorter intervals first (e.g., every minute).

8. Best Practices

1. Use Task Queues for Heavy Work

Offload CPU-heavy tasks to worker threads:

const { Worker } = require('worker_threads');

cron.schedule('0 * * * *', () => {
  const worker = new Worker('./path/to/worker.js');
});
Enter fullscreen mode Exit fullscreen mode

2. Handle Failures Gracefully

// With agenda (automatic retries)
agenda.define('critical-job', { concurrency: 1, maxAttempts: 3 }, async (job) => {
  // Your logic
});

// With node-cron
cron.schedule('...', async () => {
  try {
    await criticalTask();
  } catch (err) {
    sendAlertToSlack('Cron job failed: ' + err.message);
  }
});
Enter fullscreen mode Exit fullscreen mode

3. Avoid Overlapping Jobs

Use agenda’s concurrency control or a locking mechanism:

let isJobRunning = false;

cron.schedule('*/5 * * * *', async () => {
  if (isJobRunning) return;
  isJobRunning = true;
  await longRunningTask();
  isJobRunning = false;
});
Enter fullscreen mode Exit fullscreen mode

4. Use Environment-Specific Schedules

Disable cron jobs in development:

// In your Node.js app
if (process.env.NODE_ENV === 'production') {
  cron.schedule('...', productionTask);
}
Enter fullscreen mode Exit fullscreen mode

5. Monitor Your Jobs

  • Log job start/end times.
  • Use tools like PM2 for process management:
  pm2 start app.js
  pm2 logs
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

Choose system cron if:

  • You need tasks to run independently of your Node app.
  • Your hosting provider supports crontab.

Choose node-cron if:

  • You prefer keeping jobs within your codebase.
  • You need simple in-app scheduling.

Choose agenda if:

  • You require job persistence and retries.
  • Your app already uses MongoDB.

By combining these tools with proper error handling and monitoring, you can build robust automated workflows for your Node.js backend. Happy coding! 🚀


Further Resources:


Author: Mohin Sheikh

Follow me on GitHub for more insights!

Top comments (0)