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

distributed-locks-mongodb

v1.0.3

Published

The mongodb package for the storage layer for distributed locks

Downloads

3

Readme

MongoDB Algorithm for lock guarantees

We highly depend on the fact the mongo by default uses the _id as the primary unique key for the collection, and the fact that mongo-db guarantees atomicity on a document level

Perquisites

Make sure your mongo connection has majority for write concern and read from primary for read preference to avoid any inconsistences

Acquiring Lock

We first try to get the document in mongo that has the same value for the key (checking if someone else obtained a lock on the same critical section). Plus we project the current date in mongo

db.collection('collection')
    .findOne({ _id: 'key' }, {
        projection: {
          _id: 1,
          value: 1,
          ttl: 1,
          obtained_at: 1,
          current_date: '$$NOW',
        },
    });

If returned value is null (no one has a lock on the critical section), we try to upsert a document in mongo, we use upsert since in between this step and the previous one someone else might've obtained a lock on the same critical section and it could've even expired. the fields are:

  • _id: Represents the critical section
  • value: Represents the lock that locked the critical section
  • ttl: Time to live in seconds
  • obtained_at: The time this lock was successfully acquired
this.db.collection('collection').updateOne({
          _id: 'key',
          value: 'lock-value',
        }, {
          $set: {
            _id: 'key',
            value: 'lock-value',
            ttl: 10,
          },
          $currentDate: {
            obtained_at: { $type: 'date' },
          },
        }, { upsert: true })

If this was successful then we obtained the lock on the critical section

If the returned value from step one was not null (someone else obtained a lock for the same critical section), then we can only insert a new document if that returned lock has expired.

We do a simple check from the data returned from step one

if(data.current_date > data.obtained_at + data.ttl) {
    // Lock expired try to obtain a lock for this critical section
} 
else {
    // Lock still active can't lock the same critical section
}

If the if condition was true we do the following upsert statement

await this.db?.collection<Omit<MongoDocument, 'created_at'>>(this.collectionName).updateOne({
          _id: 'key',
          value: data.value,
          obtained_at: data.obtained_at,
        }, {
          $set: {
            _id: 'key',
            value: 'lock-value',
            ttl: 10,
          },
          $currentDate: {
            obtained_at: { $type: 'date' },
          },
        }, { upsert: true });

Notice that we don't only use the _id field to upsert the document we also use the the current lock's value and it's obtained_at as again some one else might have obtained the lock on the same critical section (same _id value but different value and obtained_at). If operation was successful then we obtained the lock

Releasing Lock

A simple delete query using the _id and the lock value

this.db.collection('collection')
      .deleteOne({
        _id: 'key',
        value: 'lock-value',
      });