async-lock
Advanced tools
Comparing version 0.1.2 to 0.2.0
@@ -0,3 +1,8 @@ | ||
0.2.0 / 2015-02-21 | ||
================== | ||
* Support promise mode | ||
* Pending task limit | ||
0.1.0 / 2015-01-13 | ||
================== | ||
* Initial version |
'use strict'; | ||
var Q = require('q'); | ||
var AsyncLock = function(opts){ | ||
@@ -11,5 +13,7 @@ opts = opts || {}; | ||
this.timeout = opts.timeout || AsyncLock.DEFAULT_TIMEOUT; | ||
this.maxPending = opts.maxPending || AsyncLock.DEFAULT_MAX_PENDING; | ||
}; | ||
AsyncLock.DEFAULT_TIMEOUT = 2000; | ||
AsyncLock.DEFAULT_TIMEOUT = 10 * 1000; | ||
AsyncLock.DEFAULT_MAX_PENDING = 1000; | ||
@@ -21,3 +25,3 @@ /** | ||
* @param {function} fn async function | ||
* @param {function} cb (optional) callback function | ||
* @param {function} cb (optional) callback function, otherwise will return a promise | ||
* @param {Object} opts (optional) options | ||
@@ -30,2 +34,15 @@ */ | ||
if(typeof(fn) !== 'function'){ | ||
throw new Error('You must pass a function to execute'); | ||
} | ||
var deferred = null; | ||
if(typeof(cb) !== 'function'){ | ||
opts = cb; | ||
cb = null; | ||
// will return a promise | ||
deferred = Q.defer(); | ||
} | ||
opts = opts || {}; | ||
@@ -37,3 +54,3 @@ | ||
var done = function(){ | ||
var done = function(err, ret){ | ||
// Make sure done is only called once | ||
@@ -51,6 +68,17 @@ if(finished){ | ||
//callback | ||
if(typeof(cb) === 'function'){ | ||
cb.apply(null, arguments); | ||
//callback mode | ||
if(!deferred){ | ||
if(typeof(cb) === 'function'){ | ||
cb.apply(null, arguments); | ||
} | ||
} | ||
else{ | ||
//promise mode | ||
if(err){ | ||
deferred.reject(err); | ||
} | ||
else{ | ||
deferred.resolve(ret); | ||
} | ||
} | ||
@@ -64,4 +92,19 @@ //run next func | ||
var exec = function(){ | ||
timer = setTimeout(done.bind(null, new Error('async-lock timed out')), opts.timeout ? opts.timeout : self.timeout); | ||
fn(done); | ||
var timeout = opts.timeout ? opts.timeout : self.timeout; | ||
timer = setTimeout(done.bind(null, new Error('async-lock timed out')), timeout); | ||
// Callback mode | ||
if(fn.length === 1){ | ||
fn(done); | ||
} | ||
else{ | ||
// Promise mode | ||
Q.fcall(function(){ | ||
return fn(); | ||
}).then(function(ret){ | ||
done(null, ret); | ||
}, function(err){ | ||
done(err); | ||
}); | ||
} | ||
}; | ||
@@ -74,4 +117,13 @@ | ||
else{ | ||
this.queues[key].push(exec); | ||
if(this.queues[key].length >= this.maxPending){ | ||
done(new Error('Too much pending tasks')); | ||
} | ||
else{ | ||
this.queues[key].push(exec); | ||
} | ||
} | ||
if(deferred){ | ||
return deferred.promise; | ||
} | ||
}; | ||
@@ -78,0 +130,0 @@ |
{ | ||
"name": "async-lock", | ||
"description": "", | ||
"version": "0.1.2", | ||
"version": "0.2.0", | ||
"author": "rain1017", | ||
@@ -29,3 +29,4 @@ "private" : false, | ||
"dependencies": { | ||
"q": "~1.1.2", | ||
"lodash": "~3.2.0" | ||
}, | ||
@@ -32,0 +33,0 @@ "devDependencies": { |
@@ -17,8 +17,23 @@ # async-lock | ||
* @param {function} fn async function with node.js style | ||
* @param {function} cb (optional) callback function | ||
* @param {function} cb (optional) callback function, otherwise will return a promise | ||
* @param {Object} opts (optional) options | ||
*/ | ||
lock.acquire(key, fn, cb, opts); | ||
lock.acquire(key, function(done){ | ||
// async work | ||
done(err, ret); | ||
}, function(err, ret){ | ||
// lock released | ||
}, opts); | ||
``` | ||
## Promise mode | ||
``` | ||
lock.acquire(key, function(){ | ||
// return value or promise | ||
}).then(function(){ | ||
// lock released | ||
}); | ||
``` | ||
## Acquire multiple keys | ||
@@ -30,21 +45,25 @@ | ||
## Specify timeout | ||
## Options | ||
``` | ||
// Specify timeout | ||
var lock = new AsyncLock({timeout : 5000}); | ||
lock.acquire(key, fn, function(err){ | ||
lock.acquire(key, fn, cb, function(err, ret){ | ||
// timed out error will be returned here if fn has not return within given time | ||
}); | ||
//Specify timeout for one function | ||
// Specify timeout for one function | ||
lock.acquire(key, fn, cb, {timeout : 5000}); | ||
``` | ||
## Get running state | ||
// Set max pending tasks | ||
var lock = new AsyncLock({maxPending : 1000}); | ||
lock.acquire(key, fn, cb, function(err, ret){ | ||
// Handle too much pending error | ||
}) | ||
``` | ||
// Where there is any running or pending async function | ||
// Whether there is any running or pending async function | ||
lock.isBusy(); | ||
``` | ||
## License | ||
@@ -51,0 +70,0 @@ (The MIT License) |
'use strict'; | ||
var Q = require('q'); | ||
var _ = require('lodash'); | ||
var AsyncLock = require('../index.js'); | ||
var assert = require('assert'); | ||
Q.longStackSupport = true; | ||
describe('AsyncLock Tests', function(){ | ||
@@ -123,2 +127,54 @@ it('Single key test', function(done){ | ||
}); | ||
it('Promise mode', function(done){ | ||
var lock = new AsyncLock(); | ||
var value = 0; | ||
var concurrency = 8; | ||
Q.all(_.range(concurrency).map(function(){ | ||
return lock.acquire('key', function(){ | ||
var tmp = null; | ||
// Simulate non-atomic check and set | ||
return Q() // jshint ignore:line | ||
.delay(_.random(10)) | ||
.then(function(){ | ||
tmp = value; | ||
}) | ||
.delay(_.random(20)) | ||
.then(function(){ | ||
value = tmp + 1; | ||
}); | ||
}); | ||
})).then(function(){ | ||
assert(value === concurrency); | ||
done(); | ||
}, function(err){ | ||
done(err); | ||
}); | ||
}); | ||
it('Error handling', function(done){ | ||
var lock = new AsyncLock(); | ||
lock.acquire('key', function(){ | ||
throw new Error('error'); | ||
}).catch(function(e){ | ||
assert(e.message === 'error'); | ||
done(); | ||
}); | ||
}); | ||
it('Too much pending', function(done){ | ||
var lock = new AsyncLock({maxPending : 1}); | ||
lock.acquire('key', function(){ | ||
return Q().delay(20); // jshint ignore:line | ||
}); | ||
lock.acquire('key', function(){ | ||
return Q().delay(20); // jshint ignore:line | ||
}); | ||
lock.acquire('key', function(){}) | ||
.catch(function(e){ | ||
done(); | ||
}); | ||
}); | ||
}); |
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
16867
372
87
2
+ Addedlodash@~3.2.0
+ Addedq@~1.1.2
+ Addedlodash@3.2.0(transitive)
+ Addedq@1.1.2(transitive)