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

mongodb-spinlock

v2.0.0

Published

Lock a mongodb collection because you chose the wrong database and need something that sort of behaves like a transaction

Downloads

6

Readme

mongo-spinlock

Circle CI Coverage Status

var spinlock = require('mongo-spinlock');

The basic idea is that operations to a collection are guarded with a lock, which is pushed on to every document in the collection. Updates are then attempted, but only performed if their lock is first (i.e. they are at the front of the queue). Other writers wait (spin) and constantly check to see if either locks that are in front have expired (i.e. the process writing to them crashed) and also update their own expiry to keep their lock alive.

Usage:

spinlock(collection, options, callback);

Simplest example:

spinlock(collection, {
    try: function(id, callback) {
		collection.update({ $isolated: 1, lock.0.id: id }, { $set: { lock.0.released: true } }, { multi: true }, callback);
    }
}, function(err) {
    // done
});

The above example is for illustration only and does not realy buy you anything because mongo can do $isolated writes in on update statement.

What is more interesting/useful is that you can issue multiple separate update operations where each one sets some value on the documents and on the lock.

spinlock(collection, {
    try: function(id, callback) {
		async.parallel([
			function(next) {
				collection.update({ $isolated: 1, lock.0.id: id }, { $set: { lock.0.stage1: true } }, { multi: true }, next);
			},
			function(next) {
				collection.update({ $isolated: 1, lock.0.id: id }, { $set: { lock.0.stage2: true } }, { multi: true }, next);
			}
		], callback);
    },
	until: { stage1: true, stage2: true }
}, function(err) {
    // done
});

Your update commands MUST ALWAYS include { $isolated: 1, lock.0.id: id } in the query part (they can include additional constraints too of course but this is what makes sure your update is happening when you 'have' the lock) (see advanced notes below)

Options

  • field: name of the field in which the locks are written to, defaults to lock
  • try: a function(id, next) that will be called every time the spinlock loops
  • until: a custom query to detect when the lock is ready to be released, defaults to { released: true }
  • subset: an additional query component applied to every operation in case your document collection has some logical subsets that can each be acccessed using different "pools" of locks.

Why :(

Well, if you needed a real database but instead chose mongodb and you need some kind of consistency fantasy between read a value -> write a value on the same collection this can accomodate that, you can use a lock, query for an item by id, and then only issue your update if the items lock[0].id is your id (just keep calling next() in try if it's not). This might just buy you enough time before everything else goes to hell.

This only works if all changes to a particular field go through a spinlock for hopefully obvious reasons.

Advanced Notes

You can issue update commands that aren't restricted to lock.0.id if they're just marking a lock as released and not modifying the object. It still goes "lock everything" then "release the unnecessary stuff".

Newly created items don't participate in the lock, so whatever logic / hopes / dreams you have needs to be able to deal with that. Also all your updates need to be idempotent and all that jazz.