From c92bc2c7422f939c7f54c66e49ff320a4ca32e93 Mon Sep 17 00:00:00 2001 From: Owen Allen Date: Mon, 4 Jan 2016 12:36:09 -0700 Subject: [PATCH 1/3] Memoize will now play nicely with Nodejs domains. --- lib/async.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/async.js b/lib/async.js index 839a66a0c..e145e2154 100644 --- a/lib/async.js +++ b/lib/async.js @@ -181,6 +181,12 @@ return iterator(value, callback); }; } + + // binds a callback to a domain, necessary in Node if a callback may be resolved in a different context, such as with memoize() + function bindToCurrentDomain(callback) { + if (typeof process !== "object" || process.domain == null || callback == null) return callback; + return process.domain.bind(callback); + } //// exported async module functions //// @@ -1095,7 +1101,7 @@ }); } else if (key in queues) { - queues[key].push(callback); + queues[key].push(bindToCurrentDomain(callback)); } else { queues[key] = [callback]; From 64a6dd568e6317c65627ea8876e4869500458402 Mon Sep 17 00:00:00 2001 From: Owen Allen Date: Mon, 4 Jan 2016 13:18:23 -0700 Subject: [PATCH 2/3] Adds test case --- test/test-async.js | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/test/test-async.js b/test/test-async.js index 05c022827..7b0cb7347 100755 --- a/test/test-async.js +++ b/test/test-async.js @@ -4309,6 +4309,72 @@ exports['memoize'] = { test.equal(val, "bar"); test.done(); }); +}, + + 'memo works with domains': function(test) { + if (isBrowser()) { + // node only test + test.done(); + return; + } + + var domain = require("domain"); + + var called = 0; + var d1Done = false; + var d2Done = false; + var d1Error = false; + var d2Error = false; + var fn = function(cb) { + called++; + setTimeout(function() { + cb(null, "done"); + }, 10); + }; + + var memo = async.memoize(fn); + + // create an initial domain, it should operate successfully and the error handler is never called + var d1 = domain.create(); + d1.on("error", function() { + d1Error = true; + }); + d1.run(function() { + setImmediate(function() { + memo(function() { + d1Done = true; + }); + }); + }); + + // if memoize does not bind our domain then our callback will end up in the context of the first callback (d1) since this callback gets queued + var d2 = domain.create(); + d2.on("error", function(err) { + d2Error = true; + test.equal(err.message, "should be caught by d2"); + }); + d2.run(function() { + setImmediate(function() { + memo(function() { + setImmediate(function() { + throw new Error("should be caught by d2"); + }); + }); + }); + }); + + var i = setInterval(function() { + if ( + d1Error === false + && d2Error === true + && d1Done === true + && d2Done === false + ) { + clearInterval(i); + test.equal(process.domain, null); + test.done(); + } + }, 5); } }; From 69dc7a4e7623bf86f751e1c7195fc0801b36199d Mon Sep 17 00:00:00 2001 From: Owen Allen Date: Mon, 4 Jan 2016 13:24:47 -0700 Subject: [PATCH 3/3] Style correction --- test/test-async.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/test-async.js b/test/test-async.js index 7b0cb7347..bc63c44bf 100755 --- a/test/test-async.js +++ b/test/test-async.js @@ -4364,12 +4364,7 @@ exports['memoize'] = { }); var i = setInterval(function() { - if ( - d1Error === false - && d2Error === true - && d1Done === true - && d2Done === false - ) { + if (d1Error === false && d2Error === true && d1Done === true && d2Done === false) { clearInterval(i); test.equal(process.domain, null); test.done();