In this lesson, you will learn how to prevent data corruption by using advisory locking to serialize access to shared files across multiple Node.js processes.
The Problem: Race Conditions
When multiple processes attempt to read from and write to the same file simultaneously, you risk a race condition. Imagine two processes reading a configuration file, modifying it, and writing it back. If Process A reads the file, then Process B reads the same file before Process A saves, Process A's changes will be completely overwritten by Process B. Because Node.js handles I/O asynchronously, these overlaps are common in high-traffic applications.
Advisory Locking Explained
File locking in Node.js is generally advisory. This means the operating system doesn't physically prevent a process from opening a file; instead, the processes "agree" to check for a lock before performing operations. If a process finds a lock, it waits or retries rather than proceeding blindly.
To implement this, we often use a library like proper-lockfile. It works by creating a "lockfile" in the file system. If the lockfile exists, other processes know the resource is busy.
Practical Implementation
Here is how you prevent a race condition by wrapping your file operations in a lock:
const lockfile = require('proper-lockfile');
const fs = require('fs/promises');
async function updateData(filePath) {
// Attempt to acquire the lock
const release = await lockfile.lock(filePath);
try {
const data = await fs.readFile(filePath, 'utf8');
const updated = JSON.parse(data) + 1;
await fs.writeFile(filePath, JSON.stringify(updated));
} finally {
// Always release the lock, even if an error occurs
await release();
}
}
In this pattern, the lockfile.lock call acts as a gatekeeper. If another process tries to acquire the lock while this one holds it, the second process will throw an error or retry, depending on your configuration. By surrounding the logic in a try...finally block, we ensure that the lock is released even if the file operation fails, preventing a "deadlock" where the file remains permanently locked.
Key Takeaway: Advisory locking ensures data integrity by creating a synchronization point that forces concurrent processes to wait their turn before modifying a shared file.