cache-manager
Advanced tools
Comparing version 0.8.0 to 0.9.0
@@ -0,1 +1,5 @@ | ||
- 0.9.0 2014-08-19 | ||
Fixing issue #8 - parallel requests to a wrapped function were calling the | ||
function multiple times. (Thanks alex-whitney). | ||
- 0.8.0 2014-07-07 | ||
@@ -2,0 +6,0 @@ Adding setex() (Thanks evanlucas) |
@@ -21,2 +21,4 @@ /*jshint maxcomplexity:10*/ | ||
self.queues = {}; | ||
/** | ||
@@ -38,17 +40,29 @@ * Wraps a function in cache. I.e., the first time the function is run, | ||
self.store.get(key, function (err, result) { | ||
if (err && (!self.ignoreCacheErrors)) { return cb(err); } | ||
if (result) { | ||
return cb(null, result); | ||
} | ||
if (err && (!self.ignoreCacheErrors)) { | ||
cb(err); | ||
} else if (result) { | ||
cb.apply(null, result); | ||
} else if (self.queues[key]) { | ||
self.queues[key].push(cb); | ||
} else { | ||
self.queues[key] = [cb]; | ||
work(function () { | ||
var work_args = Array.prototype.slice.call(arguments, 0); | ||
if (work_args[0]) { // assume first arg is an error | ||
return cb(work_args[0]); | ||
} | ||
self.store.set(key, work_args[1], function (err) { | ||
if (err && (!self.ignoreCacheErrors)) { return cb(err); } | ||
cb.apply(null, work_args); | ||
work(function () { | ||
var work_args = Array.prototype.slice.call(arguments, 0); | ||
if (work_args[0]) { // assume first arg is an error | ||
return cb(work_args[0]); | ||
} | ||
self.store.set(key, work_args, function (err) { | ||
if (err && (!self.ignoreCacheErrors)) { | ||
return cb(err); | ||
} | ||
self.queues[key].forEach(function (done) { | ||
done.apply(null, work_args); | ||
}); | ||
delete self.queues[key]; | ||
}); | ||
}); | ||
}); | ||
} | ||
}); | ||
@@ -55,0 +69,0 @@ }; |
{ | ||
"name": "cache-manager", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "Cache module for Node.js", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -238,27 +238,20 @@ // TODO: These are really a mix of unit and integration tests. | ||
it("retrieves data from memory when available", function (done) { | ||
cache.wrap(key, function (cb) { | ||
methods.get_widget(name, cb); | ||
}, function (err, widget) { | ||
check_err(err); | ||
assert.ok(widget); | ||
context("when result is already cached", function () { | ||
function get_cached_widget(name, cb) { | ||
cache.wrap(key, function (cache_cb) { | ||
methods.get_widget(name, cache_cb); | ||
}, cb); | ||
} | ||
memory_store_stub.get(key, function (err, result) { | ||
beforeEach(function (done) { | ||
get_cached_widget(name, function (err, widget) { | ||
check_err(err); | ||
assert.ok(result); | ||
assert.ok(widget); | ||
sinon.spy(memory_store_stub, 'get'); | ||
var func_called = false; | ||
memory_store_stub.get(key, function (err, result) { | ||
check_err(err); | ||
assert.ok(result); | ||
cache.wrap(key, function (cb) { | ||
methods.get_widget(name, function (err, result) { | ||
func_called = true; | ||
cb(err, result); | ||
}); | ||
}, function (err, widget) { | ||
check_err(err); | ||
assert.deepEqual(widget, {name: name}); | ||
assert.ok(memory_store_stub.get.calledWith(key)); | ||
assert.ok(!func_called); | ||
memory_store_stub.get.restore(); | ||
sinon.spy(memory_store_stub, 'get'); | ||
done(); | ||
@@ -268,2 +261,23 @@ }); | ||
}); | ||
afterEach(function () { | ||
memory_store_stub.get.restore(); | ||
}); | ||
it("retrieves data from cache", function (done) { | ||
var func_called = false; | ||
cache.wrap(key, function (cb) { | ||
methods.get_widget(name, function (err, result) { | ||
func_called = true; | ||
cb(err, result); | ||
}); | ||
}, function (err, widget) { | ||
check_err(err); | ||
assert.deepEqual(widget, {name: name}); | ||
assert.ok(memory_store_stub.get.calledWith(key)); | ||
assert.ok(!func_called); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
@@ -398,2 +412,41 @@ | ||
}); | ||
describe("when called multiple times in parallel with same key", function () { | ||
var construct; | ||
beforeEach(function () { | ||
cache = caching({ | ||
store: 'memory', | ||
max: 50, | ||
ttl: 5 * 60 | ||
}); | ||
construct = sinon.spy(function (val, cb) { | ||
var timeout = support.random.number(100); | ||
setTimeout(function () { | ||
cb(null, 'value'); | ||
}, timeout); | ||
}); | ||
}); | ||
it("calls the wrapped function once", function (done) { | ||
var values = []; | ||
for (var i = 0; i < 2; i++) { | ||
values.push(i); | ||
} | ||
async.each(values, function (val, async_cb) { | ||
cache.wrap('key', function (cb) { | ||
construct(val, cb); | ||
}, function (err, result) { | ||
assert.equal(result, 'value'); | ||
async_cb(err); | ||
}); | ||
}, function (err) { | ||
check_err(err); | ||
assert.equal(construct.callCount, 1); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -400,0 +453,0 @@ |
@@ -16,2 +16,7 @@ var fs = require('fs'); | ||
return random_str; | ||
}, | ||
number: function (max) { | ||
max = max || 1000; | ||
return Math.floor((Math.random() * max)); | ||
} | ||
@@ -18,0 +23,0 @@ }, |
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
70812
1423