Course contentsShow
← Node.js
Lesson 343 of 1,9804. I/O and File System OperationsFree lesson

Concurrency Control with File Locking

Implement advisory locking mechanisms to prevent race conditions in multi-process file access.

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.