diff --git a/lib/locallock.js b/lib/locallock.js index 4826bad..e794819 100644 --- a/lib/locallock.js +++ b/lib/locallock.js @@ -9,26 +9,48 @@ function Lock() { Lock.prototype._runOne = function(token) { var self = this; - if (locks[token].length == 0) return; + var item = _.first(locks[token]); + if (!item || item.started) return; - var task = locks[token][0]; + item.started = true; + if (item.maxRunningTime > 0) { + setTimeout(function() { + var it = _.first(locks[token]); + if (it != item) return; + locks[token].shift(); + self._runOne(token); + }, item.maxRunningTime); + } - task(null, function() { + item.fn(null, function() { locks[token].shift(); self._runOne(token); }); }; Lock.prototype.locked = function(token, wait, max, task) { + var self = this; + if (_.isUndefined(locks[token])) { locks[token] = []; } - locks[token].push(task); + var item = { + maxRunningTime: max, + started: false, + fn: task, + }; + locks[token].push(item); - if (locks[token].length == 1) { - this._runOne(token); + if (wait > 0) { + setTimeout(function() { + var it = _.find(locks[token], item); + if (!it || it.started) return; + locks[token] = _.without(locks[token], it); + it.fn(new Error('Could not acquire lock ' + token)); + }, wait); } + self._runOne(token); }; module.exports = Lock; diff --git a/test/locallock.js b/test/locallock.js index 7e0b8f5..468511e 100644 --- a/test/locallock.js +++ b/test/locallock.js @@ -56,4 +56,33 @@ describe('Local locks', function() { done(); }, 1); }); + it('should return error if unable to acquire lock', function(done) { + lock.locked('123', 0, 0, function(err, release) { + should.not.exist(err); + setTimeout(function() { + release(); + }, 5); + lock.locked('123', 1, 0, function(err, release) { + should.exist(err); + err.toString().should.contain('Could not acquire lock 123'); + done(); + }); + }); + }); + it('should release lock if acquired for a long time', function(done) { + var i = 0; + lock.locked('123', 0, 3, function(err, release) { + should.not.exist(err); + i++; + lock.locked('123', 15, 0, function(err, release) { + should.not.exist(err); + i++; + }); + }); + setTimeout(function() { + i.should.equal(2); + done(); + }, 10); + }); + });