Registry / database / rwlockfile

rwlockfile

JSON →
library2.0.25jsnpmunverified

rwlockfile is a Node.js utility that provides a file-based readers-writers lock mechanism, allowing multiple readers or a single writer to access a resource. It is currently at version 2.0.25 and appears to be actively maintained as needed. A key differentiator is its explicit support for the standard Readers-Writers Lock design pattern, which the author claims is unique among Node.js packages. Unlike simpler lockfile solutions, rwlockfile allows for flexible, nested locking logic on a single `RWLockfile` instance, where `add()` and `remove()` methods manage an internal counter to ensure the physical lock is only held when needed and released only when all nested calls are complete. This makes it suitable for complex asynchronous workflows requiring fine-grained concurrency control over shared resources.

npm install rwlockfile
INSTALL
IMPORT
SIG · RWLOCKFILE
R
rwlockfile
databasejavascriptv2.0.25
Install
Import
Disk
Pass rate
0/ 6
Env Coverage0 / 6
glibc
1822
musl
1822
Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
node 18226 runs
build_error
glibc
node 18226 runs
build_error
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

RWLockfile
import { RWLockfile } from 'rwlockfile';
import RWLockfile from 'rwlockfile';
RWLockfile is a named export. ESM import should use destructuring. CommonJS also uses destructuring from `require()`.
RWLockfile
const { RWLockfile } = require('rwlockfile');
const RWLockfile = require('rwlockfile');
Even in CommonJS, the `RWLockfile` class is a named export and must be destructured from the `require()` call.
RWLockfileOptions
import type { RWLockfileOptions } from 'rwlockfile';
import { RWLockfileOptions } from 'rwlockfile';
For TypeScript users, import types using `import type` to prevent runtime import issues if not bundled correctly, though direct named import `import { RWLockfileOptions } from 'rwlockfile'` often works if tree-shaking is effective.

Demonstrates basic synchronous and asynchronous usage of `RWLockfile` for establishing read and write locks, including an example of the instance-specific nested lock handling described in the documentation, showcasing how `add` and `remove` manage an internal counter before affecting the actual file lock.

import { RWLockfile } from 'rwlockfile'; async function runLockExample() { // 'lockfile-target' is the base path; '.lock' will be appended for the actual lock file. const lock = new RWLockfile('lockfile-target', { timeout: 5000, // Wait up to 5 seconds for a lock retryInterval: 50 // Check every 50ms }); try { console.log('Attempting to acquire a write lock...'); await lock.add('write'); console.log('Write lock acquired. Performing critical write operation...'); await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate work console.log('Write operation complete. Releasing lock.'); } finally { await lock.remove('write'); console.log('Write lock released.'); } console.log('\nAttempting to acquire a read lock...'); await lock.add('read'); try { console.log('Read lock acquired. Performing read operation...'); await new Promise(resolve => setTimeout(resolve, 500)); // Simulate work console.log('Read operation complete. Releasing lock.'); } finally { await lock.remove('read'); console.log('Read lock released.'); } // Demonstrate nested locking (instance-specific counting) async function nestedWrite() { await lock.add('write'); try { console.log(' Nested write lock added by inner function.'); await new Promise(resolve => setTimeout(resolve, 200)); } finally { await lock.remove('write'); console.log(' Nested write lock removed by inner function.'); } } try { console.log('\nAttempting top-level write lock for nesting...'); await lock.add('write'); console.log('Top-level write lock acquired.'); await nestedWrite(); // Call a function that also adds/removes a lock on the same instance console.log('Back in top-level. Main write operation continuing.'); await new Promise(resolve => setTimeout(resolve, 300)); } finally { await lock.remove('write'); console.log('Top-level write lock finally released after all nested calls.'); } } runLockExample().catch(console.error);
Debug
Known issues
gotchaThe `add()` and `remove()` methods manage an internal counter on the `RWLockfile` instance itself, not directly reflecting the global lock status for each call. A physical lock is acquired or released only when this internal counter crosses the 0/1 threshold. This design enables nested function calls to acquire locks without releasing the global lock prematurely, but it can be counter-intuitive if expecting a one-to-one correspondence between method calls and file lock state changes.
fix
Always pair `add()` with a `remove()` call within a `try...finally` block to ensure locks are properly decremented, especially in asynchronous code. Understand that multiple `add('write')` calls on the same instance before a `remove('write')` will only hold one actual file-system write lock.
affects: >=1.0.0
gotchaIf the process holding a lock crashes abruptly without calling `remove()`, the lockfile may become stale, preventing other processes from acquiring the lock. While the library supports timeouts for acquiring locks, it doesn't automatically detect and clean up stale locks from crashed processes.
fix
Implement external cleanup mechanisms for environments where processes might crash (e.g., cron jobs to remove old lockfiles, or a separate heartbeat mechanism). Consider using shorter `timeout` values and robust error handling to recover from potential deadlocks.
affects: >=1.0.0
gotchaThe `retryInterval` option, which specifies the minimum time between lock checks, can significantly impact performance or the responsiveness of lock acquisition. A very low interval can lead to high CPU usage due to frequent file system polling, while a high interval can make lock acquisition slow and unresponsive.
fix
Adjust `retryInterval` based on your application's specific needs, balancing responsiveness with resource usage. The library automatically adds some noise and duplicates this number each check, so a base value between 50ms and 500ms is often a good starting point, depending on disk I/O characteristics and expected lock contention.
affects: >=1.0.0
Errors
Common errors & fixes
Error: ETIMEDOUT: acquire lock timeout
The lock could not be acquired within the specified `timeout` period, likely because another process held the lock for too long or a stale lockfile was present.
fix
Increase the `timeout` option when initializing `RWLockfile` if the wait time is acceptable, or investigate the cause of long-held locks. Ensure `remove()` is always called in `finally` blocks. Manually clean up any stale lockfiles from crashed processes if necessary.
TypeError: RWLockfile is not a constructor
Incorrect import statement, attempting to use `require('rwlockfile')` or `import RWLockfile from 'rwlockfile'` directly as the constructor without destructuring.
fix
Use `const { RWLockfile } = require('rwlockfile');` for CommonJS or `import { RWLockfile } from 'rwlockfile';` for ESM, as `RWLockfile` is a named export.
Upgrade
Version history
2.0.25latest on npm
Audit
Dependencies

No dependency data recorded yet.

Agent activity
15 hits · last 30 days
node
12
Meta
1
OpenAI (training)
1
Resources
rwlockfile — npm install rwlockfile · libregistry