npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

rwlock-plus

v1.0.0

Published

concurrency locking for nodejs

Downloads

8

Readme

###rwlock-plus

Extends rwlock with lock expiration and automatic invocation of a callback.

###usage

See rwlock for more details on the general locking concepts. An instance of rwlock-plus has this API:

locker.readLock(key, releaseCallback, lockObtainedCallback)
locker.writeLock(key, releaseCallback, lockObtainedCallback)
  • A read lock prevents a write lock from being obtained until it is released.
  • A write lock prevents any other lock from being obtained until it is released.

When locks are requested but not obtained, they are queued, and provisioned to the requester in the order received. This behavior is applied across each unique key. That is, locks obtained with different keys are completely independent.

When a lock is obtained, the lockObtainedCallback is invoked with a single parameter, a function release() which should be invoked to release the lock. If a releaseCallback was provided, then invoking release will release the lock and also invoke releaseCallback with any arguments provided. This encapsulates a common use case - releasing the lock and subsequently invoking the method's original callback.

Arguments passed to release will be forwarded to releaseCallback. Therefore, if the original callback has an error argument as its first parameter, calling release with an error will respect the underlying api and pass the error the the callback. Since there are no error conditions associated with the lock obtained callback, there is no error argument.

#####expirations

Locks can have expirations, after a duration defined when creating an instance of rwlock-plus. If an expiration is defined, it will cause any unreleased lock to automatically be released if another lock is waiting for the resource. That is, if nothing else has requested a lock for a given resource, then the lock will never expire automatically. However, if something subsequently requests a lock on a resource with an expired lock, it will be release immediately. When a lock is released as a result of expiration, the original callback (if provided) will be invoked with an error.

var Lock = require('rwlock-plus')
...

var lock = new Lock();

lock.readLock('my-resource', callback, function (release) {
    // do stuff

    release();
});

key is required; any locks on the same key are held across any other locks requested for the same key.

#####calling back before releasing the lock

When release is called, it also invokes callback. This ensures you will always release your locks before calling the callback. In situations where you want to call the callback without release a lock, e.g. you return a resource immediately that must remain locked until some activity completes, such a stream, you can omit this parameter:

var lock = new Lock();

function GetStream(err, callback) {	
	lock.readLock('my-resource', null, function (release) {
	    var stream = GetStream();
	    stream.on('end', release);
	   	callback(stream);
	});
});

Note that this introduces risk of a lock never being released, if, for example, the stream never emits 'end.' You can address this with a failsafe:

var lock = new Lock(10000); // 10 second maximum time to hold a lock

The same code above is safe now: if 10 seconds pass, the lock will be released. When a lock times out, the release callback will be invoked with an Error argument. If you need to do some cleanup or special handling when the timeout occurs, use the releaseCallback to deal with this:

function GetStream(err, callback) {	
    var stream;

	function released(err) {
		if (err) {
            stream.abort();
            logger.warn("Stream timed out")
        }
	}

	lock.readLock(key, released, function (release) {
	    stream = GetStream();
	    stream.on('end', release);
	    callback(stream);
	});
});

The workflow here is:

  • When lock is obtained, callback is immediately invoked with the stream.
  • When the stream end event fires, the lock is released. This also invokes released but with no argument.
  • If 10 seconds pass before the stream end event fires, released is invoked with an Error.

Note that it's entirely possible that the end event could later fire after a timeout in this code, causing release to be invoked again. While it probably should be improved to prevent this by unbinding the event in that scenario, if release should be called again, nothing will happen: the lockReleased callback will never be invoked more than once by rwlock-plus even if the release method is called multiple times.