consul-locker

0.0.1 • Public • Published

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.

Readme

Keywords

none

Package Sidebar

Install

npm i consul-locker

Weekly Downloads

2

Version

0.0.1

License

MIT

Last publish

Collaborators

  • arobson
  • brian_edgerton