proper-lockfile vs async-lock vs lockfile
Node.js Locking Mechanisms Comparison
1 Year
proper-lockfileasync-locklockfileSimilar Packages:
What's Node.js Locking Mechanisms?

Locking mechanisms in Node.js are essential for managing concurrent access to resources, ensuring data integrity, and preventing race conditions. These packages provide various approaches to implement locks, allowing developers to synchronize access to shared resources effectively. Each package has its unique features and use cases, catering to different scenarios in asynchronous programming and file management.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
proper-lockfile2,641,452244-194 years agoMIT
async-lock2,397,22440518.3 kB6a year agoMIT
lockfile1,601,293260-127 years agoISC
Feature Comparison: proper-lockfile vs async-lock vs lockfile

Locking Mechanism

  • proper-lockfile:

    proper-lockfile enhances the file locking approach by providing additional features such as automatic removal of stale locks and support for multiple lock types. It ensures that locks are properly managed and released, preventing issues related to orphaned lock files and improving overall reliability in file access.

  • async-lock:

    async-lock provides a simple API for creating locks around asynchronous functions. It allows you to define critical sections of code that should not be executed concurrently, ensuring that only one instance of a function can run at a time. This is particularly useful for managing shared resources in a non-blocking manner, making it ideal for Node.js applications.

  • lockfile:

    lockfile implements a file-based locking mechanism, creating a lock file that indicates a resource is in use. When a process attempts to access a locked resource, it will check for the existence of the lock file, preventing simultaneous access. This approach is straightforward and effective for managing file access in multi-process environments.

Use Cases

  • proper-lockfile:

    proper-lockfile is designed for more complex applications that require robust file locking mechanisms. It is suitable for scenarios where you need to ensure that locks are properly cleaned up and managed, such as in long-running processes or applications with multiple file access points.

  • async-lock:

    async-lock is best suited for scenarios where you need to manage access to shared resources in asynchronous code, such as database operations or API calls. It is ideal for preventing race conditions in applications that rely heavily on asynchronous processing.

  • lockfile:

    lockfile is particularly useful in situations where multiple processes need to read or write to the same file, such as in build systems or data processing pipelines. It ensures that only one process can modify a file at a time, preventing data corruption and ensuring consistency.

Simplicity vs. Features

  • proper-lockfile:

    proper-lockfile is feature-rich, offering advanced functionalities that may require a deeper understanding of its API. It is suitable for developers who need comprehensive control over file locking and are willing to invest time in understanding its capabilities.

  • async-lock:

    async-lock offers a minimalist approach, focusing on simplicity and ease of use. Its API is straightforward, making it easy to integrate into existing codebases without a steep learning curve.

  • lockfile:

    lockfile strikes a balance between simplicity and functionality. It provides a clear API for managing lock files, making it easy to implement file locking without overwhelming complexity.

Performance

  • proper-lockfile:

    proper-lockfile may have slightly more overhead due to its additional features, but it provides a more robust solution for managing file locks, making it suitable for applications where reliability is paramount.

  • async-lock:

    async-lock is optimized for performance in asynchronous environments, allowing for quick acquisition and release of locks without blocking the event loop. This ensures that your application remains responsive even when managing locks.

  • lockfile:

    lockfile's performance is generally good for file locking scenarios, but it may introduce some overhead due to file system operations. However, it is efficient for most use cases involving file access control.

Error Handling

  • proper-lockfile:

    proper-lockfile offers comprehensive error handling, including automatic recovery from stale locks and detailed error messages. This makes it easier for developers to diagnose issues related to file locking and ensures smoother operation in complex applications.

  • async-lock:

    async-lock provides basic error handling capabilities, allowing developers to handle exceptions that may occur during lock acquisition or release. This helps maintain application stability in case of unexpected issues.

  • lockfile:

    lockfile includes error handling for scenarios where lock acquisition fails, providing feedback to the user or developer about the locking status. This is crucial for debugging and ensuring that processes do not hang indefinitely.

How to Choose: proper-lockfile vs async-lock vs lockfile
  • proper-lockfile:

    Choose proper-lockfile if you require a more robust and feature-rich file locking solution. It offers additional functionalities such as automatic cleanup of stale locks and support for multiple lock types. This package is suitable for complex applications where file integrity and process coordination are critical.

  • async-lock:

    Choose async-lock if you need a simple and lightweight solution for managing asynchronous locks in JavaScript. It is particularly useful for controlling access to critical sections of code in an asynchronous environment, making it ideal for scenarios where you want to prevent concurrent execution of specific functions.

  • lockfile:

    Choose lockfile if your primary focus is on file locking mechanisms. It provides a straightforward way to create and manage lock files, ensuring that only one process can access a resource at a time. This is particularly useful in scenarios where multiple processes may attempt to read or write to the same file, preventing data corruption.

README for proper-lockfile

proper-lockfile

NPM version Downloads Build Status Coverage Status Dependency status Dev Dependency status

An inter-process and inter-machine lockfile utility that works on a local or network file system.

Installation

$ npm install proper-lockfile

Design

There are various ways to achieve file locking.

This library utilizes the mkdir strategy which works atomically on any kind of file system, even network based ones. The lockfile path is based on the file path you are trying to lock by suffixing it with .lock.

When a lock is successfully acquired, the lockfile's mtime (modified time) is periodically updated to prevent staleness. This allows to effectively check if a lock is stale by checking its mtime against a stale threshold. If the update of the mtime fails several times, the lock might be compromised. The mtime is supported in almost every filesystem.

Comparison

This library is similar to lockfile but the latter has some drawbacks:

  • It relies on open with O_EXCL flag which has problems in network file systems. proper-lockfile uses mkdir which doesn't have this issue.

O_EXCL is broken on NFS file systems; programs which rely on it for performing locking tasks will contain a race condition.

  • The lockfile staleness check is done via ctime (creation time) which is unsuitable for long running processes. proper-lockfile constantly updates lockfiles mtime to do proper staleness check.

  • It does not check if the lockfile was compromised which can lead to undesirable situations. proper-lockfile checks the lockfile when updating the mtime.

  • It has a default value of 0 for the stale option which isn't good because any crash or process kill that the package can't handle gracefully will leave the lock active forever.

Compromised

proper-lockfile does not detect cases in which:

  • A lockfile is manually removed and someone else acquires the lock right after
  • Different stale/update values are being used for the same file, possibly causing two locks to be acquired on the same file

proper-lockfile detects cases in which:

  • Updates to the lockfile fail
  • Updates take longer than expected, possibly causing the lock to become stale for a certain amount of time

As you see, the first two are a consequence of bad usage. Technically, it was possible to detect the first two but it would introduce complexity and eventual race conditions.

Usage

.lock(file, [options])

Tries to acquire a lock on file or rejects the promise on error.

If the lock succeeds, a release function is provided that should be called when you want to release the lock. The release function also rejects the promise on error (e.g. when the lock was already compromised).

Available options:

  • stale: Duration in milliseconds in which the lock is considered stale, defaults to 10000 (minimum value is 5000)
  • update: The interval in milliseconds in which the lockfile's mtime will be updated, defaults to stale/2 (minimum value is 1000, maximum value is stale/2)
  • retries: The number of retries or a retry options object, defaults to 0
  • realpath: Resolve symlinks using realpath, defaults to true (note that if true, the file must exist previously)
  • fs: A custom fs to use, defaults to graceful-fs
  • onCompromised: Called if the lock gets compromised, defaults to a function that simply throws the error which will probably cause the process to die
  • lockfilePath: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass file as <dir path> and options.lockfilePath as <dir path>/dir.lock
const lockfile = require('proper-lockfile');

lockfile.lock('some/file')
.then((release) => {
    // Do something while the file is locked

    // Call the provided release function when you're done,
    // which will also return a promise
    return release();
})
.catch((e) => {
    // either lock could not be acquired
    // or releasing it failed
    console.error(e)
});

// Alternatively, you may use lockfile('some/file') directly.

.unlock(file, [options])

Releases a previously acquired lock on file or rejects the promise on error.

Whenever possible you should use the release function instead (as exemplified above). Still there are cases in which it's hard to keep a reference to it around code. In those cases unlock() might be handy.

Available options:

  • realpath: Resolve symlinks using realpath, defaults to true (note that if true, the file must exist previously)
  • fs: A custom fs to use, defaults to graceful-fs
  • lockfilePath: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass file as <dir path> and options.lockfilePath as <dir path>/dir.lock
const lockfile = require('proper-lockfile');

lockfile.lock('some/file')
.then(() => {
    // Do something while the file is locked

    // Later..
    return lockfile.unlock('some/file');
});

.check(file, [options])

Check if the file is locked and its lockfile is not stale, rejects the promise on error.

Available options:

  • stale: Duration in milliseconds in which the lock is considered stale, defaults to 10000 (minimum value is 5000)
  • realpath: Resolve symlinks using realpath, defaults to true (note that if true, the file must exist previously)
  • fs: A custom fs to use, defaults to graceful-fs
  • lockfilePath: Custom lockfile path. e.g.: If you want to lock a directory and create the lock file inside it, you can pass file as <dir path> and options.lockfilePath as <dir path>/dir.lock
const lockfile = require('proper-lockfile');

lockfile.check('some/file')
.then((isLocked) => {
    // isLocked will be true if 'some/file' is locked, false otherwise
});

.lockSync(file, [options])

Sync version of .lock().
Returns the release function or throws on error.

.unlockSync(file, [options])

Sync version of .unlock().
Throws on error.

.checkSync(file, [options])

Sync version of .check(). Returns a boolean or throws on error.

Graceful exit

proper-lockfile automatically removes locks if the process exits, except if the process is killed with SIGKILL or it crashes due to a VM fatal error (e.g.: out of memory).

Tests

$ npm test
$ npm test -- --watch during development

The test suite is very extensive. There's even a stress test to guarantee exclusiveness of locks.

License

Released under the MIT License.