rwlockfile
v2.0.25
Published
lockfile utility with reader/writers
Downloads
13,021
Readme
rwlockfile
node utility for read/write lockfiles
This is the only node package as of this writing I'm aware of that allows you to have read/write lockfiles. If you're looking for a simpler solution, check out proper-lockfile. Use this package if you need read/write lock support.
This follows the standard Readers-Writers Lock design pattern. Any number of readers are allowed at one time. 1 writer is allowed at one time iff there are no current readers.
Usage
const {RWLockfile} = require('rwlockfile')
// 'myfile' is the path to a file to use as the base for the lockfile
// it will add '.lock' to the end for the actual lockfile, so in this case 'myfile.lock'
let lock = new RWLockfile('myfile', {
// how long to wait until timeout. Default: 30000
timeout: 30000,
// mininum time to wait between checking for locks
// automatically adds some noise and duplicates this number each check
retryInterval: 10,
})
// add a reader async or synchronously. If the count is >= 1 it creates a read lock (see note below)
await lock.add('read')
lock.addSync('read')
// remove a reader async or synchronously. If the count == 0 it creates removes the read lock
await lock.remove('read')
lock.removeSync('read')
// add a writer async or synchronously
await lock.add('write')
lock.addSync('write')
Behavior Note
The use of .add()
and .remove()
may be a bit misleading but allow me to attempt to explain what it means. It's designed to make it easy to add try/finally steps around locking. Each instance of RWLockfile has a count of readers and writers. The file itself has it's own count of readers and writers. When you increment the count, what you're doing is adding to the count of just that instance.
In other words, you can do lock.add('write')
multiple times on the same instance. That instance will create the write lock if the count is greater than 1 but no other instances will be allowed to increase the count above 0.
Why? Because this way you can have functions in your code like this:
async function doAThing() {
await lock.add('write')
try {
// do something while locked
doAnotherThing()
} finally {
await lock.remove('write')
}
}
async function doAnotherThing() {
await lock.add('write')
try {
// do something else while locked
} finally {
await lock.remove('write')
}
}
This will only create a single write lock which will be removed after doAThing() is done. This way you can call doAnotherThing() and it ensures it has a lock if it doesn't exist, but will only remove the write lock if nothing it's using also has a write lock.
I've found this behavior to be perfect for working with, but this sort of nesting lock logic is a little difficult to explain.