node-redis-warlock
Advanced tools
Comparing version 0.0.7 to 0.1.1
var crypto = require('crypto'); | ||
var Scripty = require('node-redis-scripty'); | ||
var UUID = require('uuid'); | ||
@@ -12,3 +13,3 @@ var scripty; | ||
warlock.makeKey = function(key) { | ||
return 'lock:' + crypto.createHash('md5').update(key).digest('hex').substr(0, 10); | ||
return key + ':lock'; | ||
}; | ||
@@ -25,18 +26,21 @@ | ||
if (typeof key !== 'string') return cb(new Error('lock key must be string')); | ||
if (typeof key !== 'string') { | ||
return cb(new Error('lock key must be string')); | ||
} | ||
scripty.loadScriptFile('lock', __dirname + '/lua/lock.lua', function(err, lock){ | ||
if (err) return cb(err); | ||
var timestamp = Date.now(); | ||
lock.run(3, warlock.makeKey(key), ttl, timestamp, function(err, lockSet) { | ||
var id; | ||
UUID.v1(null, (id = new Buffer(16))); | ||
id = id.toString('base64'); | ||
redis.set( | ||
warlock.makeKey(key), id, | ||
'PX', ttl, 'NX', | ||
function(err, lockSet) { | ||
if (err) return cb(err); | ||
var unlock = warlock.unlock.bind(warlock, key, timestamp); | ||
var unlock = warlock.unlock.bind(warlock, key, id); | ||
if (!lockSet) unlock = false; | ||
return cb(err, unlock); | ||
}); | ||
}); | ||
} | ||
); | ||
@@ -46,15 +50,51 @@ return key; | ||
warlock.unlock = function(key, timestamp, cb) { | ||
warlock.unlock = function(key, id, cb) { | ||
cb = cb || function(){}; | ||
if (typeof key !== 'string') return cb(new Error('lock key must be string')); | ||
if (typeof key !== 'string') { | ||
return cb(new Error('lock key must be string')); | ||
} | ||
scripty.loadScriptFile('parityDel', __dirname + '/lua/parityDel.lua', function(err, parityDel){ | ||
if (err) return cb(err); | ||
scripty.loadScriptFile( | ||
'parityDel', | ||
__dirname + '/lua/parityDel.lua', | ||
function(err, parityDel){ | ||
if (err) return cb(err); | ||
return parityDel.run(2, warlock.makeKey(key), timestamp, cb); | ||
}); | ||
return parityDel.run(2, warlock.makeKey(key), id, cb); | ||
} | ||
); | ||
}; | ||
/** | ||
* Set a lock optimistically (retries until reaching maxAttempts). | ||
*/ | ||
warlock.optimistic = function(key, ttl, maxAttempts, wait, cb) { | ||
var attempts = 0; | ||
var tryLock = function() { | ||
attempts += 1; | ||
warlock.lock(key, ttl, function(err, unlock) { | ||
if (err) return cb(err); | ||
if (typeof unlock !== 'function') { | ||
if (attempts >= maxAttempts) { | ||
var e = new Error('unable to obtain lock'); | ||
e.maxAttempts = maxAttempts; | ||
e.key = key; | ||
e.ttl = ttl; | ||
e.wait = wait; | ||
return cb(e); | ||
} | ||
return setTimeout(tryLock, wait); | ||
} | ||
return cb(err, unlock); | ||
}); | ||
}; | ||
tryLock(); | ||
}; | ||
return warlock; | ||
}; |
{ | ||
"name": "node-redis-warlock", | ||
"version": "0.0.7", | ||
"version": "0.1.1", | ||
"description": "Battle-hardened distributed locking using redis", | ||
@@ -25,3 +25,4 @@ "main": "lib/warlock.js", | ||
"dependencies": { | ||
"node-redis-scripty": "~0.0.4" | ||
"node-redis-scripty": "~0.0.4", | ||
"uuid": "^1.4.1" | ||
}, | ||
@@ -31,4 +32,5 @@ "devDependencies": { | ||
"mocha": "^1.17.1", | ||
"redis": "^0.10.1" | ||
"redis": "^0.10.1", | ||
"async": "^0.9.0" | ||
} | ||
} |
@@ -9,3 +9,3 @@ warlock | ||
* [node-redis](https://github.com/mranney/node_redis) compatible with `v0.10` | ||
* Redis `v2.6` or above | ||
* Redis `v2.6.12` or above. If you're running a Redis version from `v2.6.0` to `v2.6.11` inclusive use `v0.0.7` of this module. | ||
@@ -29,3 +29,3 @@ ## Install | ||
var key = 'test-lock'; | ||
var ttl = 10000; | ||
var ttl = 10000; // Lifetime of the lock | ||
@@ -51,2 +51,9 @@ warlock.lock(key, ttl, function(err, unlock){ | ||
// set a lock optimistically | ||
var key = 'opt-lock'; | ||
var ttl = 10000; | ||
var maxAttempts = 4; // Max number of times to try setting the lock before erroring | ||
var wait = 1000; // Time to wait before another attempt if lock already in place | ||
warlock.optimistic(key, ttl, maxAttempts, wait, function(err, unlock) {}); | ||
``` | ||
@@ -56,3 +63,2 @@ | ||
* Warlock uses Lua scripting to achieve transactional locking on Redis `v2.6.0` upwards. If you're running Redis `v2.6.12` or above you could use the additional PX and NX arguments for the [SET](http://redis.io/commands/set) operation as an alternative. | ||
* Read my [Distributed locks using Redis](https://engineering.gosquared.com/distributed-locks-using-redis) article and Redis' author's [A proposal for more reliable locks using Redis](http://antirez.com/news/77) to learn more about the theory of distributed locks using Redis. |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
8743
12
147
61
2
4
+ Addeduuid@^1.4.1
+ Addeduuid@1.4.2(transitive)