In this lesson, you will learn how to ensure that a scheduled task executes exactly once across a cluster of Node.js instances by utilizing distributed locking.
The Challenge of Multi-Instance Scheduling
When running a Node.js application, you often scale horizontally by spinning up multiple instances. If you have a task scheduled to run every hour (using node-cron or a similar tool), every single instance will wake up and trigger that task simultaneously. This redundancy is often disastrous—leading to duplicate emails, double-charged payments, or database race conditions.
The Solution: Distributed Locking
To prevent this, we introduce a Distributed Lock. Instead of simply running the task, every instance attempts to "acquire" a temporary key in a shared data store (like Redis) before proceeding.
Think of it as a game of musical chairs: the first instance to write the key with a short Time-To-Live (TTL) wins the right to execute. If another instance tries to write the same key, it realizes the lock is already held and gracefully skips the task.
Implementation Pattern
Using a library like redlock or a simple Redis SET NX command, the logic looks like this:
async function runScheduledTask() {
const lockKey = 'task:daily-report';
const ttl = 5000; // 5 seconds to hold the lock
// Attempt to acquire lock
const acquired = await redis.set(lockKey, 'locked', 'NX', 'PX', ttl);
if (!acquired) {
console.log('Task already running elsewhere, skipping.');
return;
}
try {
await performBusinessLogic();
} finally {
// Release the lock so the next cycle can proceed
await redis.del(lockKey);
}
}
Why this works
By relying on an external, centralized store, your instances stop acting as isolated silos and start acting as a coordinated system. The TTL ensures that if an instance crashes during the task, the lock eventually expires, allowing the system to recover automatically—linking back to our previous lessons on Designing for Disaster Recovery.
Key Takeaway: Use a shared, atomic data store to acquire an expiring lock before executing a periodic task to ensure that only one instance in your cluster performs the work.