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 🙏

© 2024 – Pkg Stats / Ryan Hefner

consul-locker

v0.0.1

Published

Distributed locks using Consul

Downloads

4

Readme

consul-locker

This library uses Consul sessions to implement distributed locking. It uses Leader Election to give out locks one at a time.

Usage

Simple example:

var locker = require( "consul-locker" )();

var myLocker = locker.create({
	name: "resourceWriter"
});

myLocker.lock( 123 )
	.then( function() {
		// YAY! You got a lock
		db.writeSomethingAwesome({ id: 123 });
	}, function( err ) {
		// Sorry, no lock for you. Please don't write anything
		abort();
	});

Competing lockers:


var locker1 = locker.create({
	name: "resourceWriter"
});

var locker2 = locker.create({
	name: "resourceWriter" // Lockers contending for the same keyspace, need to have the same name
});

locker1.lock( "someid" )
	.then( function() {
		// Lock acquired.
	});

// ... Later on

locker2.lock( "someid" )
	.then( null, function( err ) {
		// Lock could not be acquired
		console.log( err ); // Already locked
	});

Releasing a lock:

locker1.release( "someid" )
	.then( function() {
		// Now it can be acquired by a different locker
	});

API

Locker Factory

The factory function returned when the module is required accepts a configuration object that is passed into the consul library used internally. From their documentation, it supports:

  • host (String, default: 127.0.0.1): agent address
  • port (String, default: 8500): agent HTTP(S) port
  • secure (Boolean, default: false): enable HTTPS
  • ca (String[], optional): array of strings or Buffers of trusted certificates in PEM format

Example:

var lockerFactory = require( "consul-locker" )({
	host: "otherhost.com"
});

The locker factory returns an object with a single method;

| Method | Description | | --------------------- | ----------- | | create([config]) | Creates a new locker instance |

Available configuration options:

  • name: (String) The name of the session. Used as the key prefix for generating lock keys.

  • maxRetries: (Number) The number of times the locker will reattempt to create a session if the initial creation fails. Defaults to 10.

  • retryInterval: (Number) The number of seconds to wait between retries. Defaults to 30.

IMPORTANT: The name property is used to create keys for locking. Therefore, if you want lockers to compete in the same keyspace, you'll have to name them the same thing. Otherwise, they will all compete in their own keyspace which means they will always win their locks and you will lose.

Example:

var myLocker = lockerFactory.create({
	name: "userTableWriter"
});

Locker Object

| Method | Description | | ------------------| ----------- | | create( id ) | Attempts to acquire the lock from Consul | | release( id ) | Releases the lock in Consul |

How it works

If you've made it this far, you're probably wondering how this library implements leader election. Here is what happens when the library is used:

Step 1:

var lockerFactory = require( "consul-locker" )();

An instance of node-consul is created with the given connection information.

Step 2:

var myLocker = lockerFactory.create({
	name: "writerService"
});

A new instance of the Locker state machine is created and returned. It immediately begins trying to create a session on the consul agent while buffering any attempts to lock until after the session is established.

The returned session ID is stored internally and used as part of every lock acquisition request.

Step 3:

myLocker.lock( "someid" )
	.then(function() {
		// Start writing
	})

A request is made to consul to set a key called /writerService/someid/lock?acquire=SESSION_ID. Consul will return true if the key can be set and false if it cannot. If it cannot, then it has been locked by another session. The locker will resolve or reject the lock call depending on the result of this call.

consul-locker assumes that locks will be long lived and will caches acquired locks so that additional requests do not need to be made.