Merge pull request #885 from projectxmaker/master

MongoDB - loopback.getCurrentContext() returns null

Close #885
Fix #809
This commit is contained in:
Miroslav Bajtoš 2015-01-07 10:57:14 +01:00
commit 989abf6822
2 changed files with 91 additions and 6 deletions

View File

@ -2,6 +2,7 @@ var loopback = require('../../lib/loopback');
var juggler = require('loopback-datasource-juggler'); var juggler = require('loopback-datasource-juggler');
var remoting = require('strong-remoting'); var remoting = require('strong-remoting');
var cls = require('continuation-local-storage'); var cls = require('continuation-local-storage');
var domain = require('domain');
module.exports = context; module.exports = context;
@ -44,6 +45,13 @@ function context(options) {
var scope = options.name || name; var scope = options.name || name;
var enableHttpContext = options.enableHttpContext || false; var enableHttpContext = options.enableHttpContext || false;
var ns = createContext(scope); var ns = createContext(scope);
var currentDomain = process.domain = domain.create();
currentDomain.oldBind = currentDomain.bind;
currentDomain.bind = function(callback, context) {
return currentDomain.oldBind(ns.bind(callback, context), context);
};
// Return the middleware // Return the middleware
return function contextHandler(req, res, next) { return function contextHandler(req, res, next) {
if (req.loopbackContext) { if (req.loopbackContext) {
@ -53,13 +61,19 @@ function context(options) {
// Bind req/res event emitters to the given namespace // Bind req/res event emitters to the given namespace
ns.bindEmitter(req); ns.bindEmitter(req);
ns.bindEmitter(res); ns.bindEmitter(res);
currentDomain.add(req);
currentDomain.add(res);
// Create namespace for the request context // Create namespace for the request context
ns.run(function processRequestInContext(context) { currentDomain.run(function() {
// Run the code in the context of the namespace ns.run(function processRequestInContext(context) {
if (enableHttpContext) { // Run the code in the context of the namespace
ns.set('http', {req: req, res: res}); // Set up the transport context if (enableHttpContext) {
} ns.set('http', {req: req, res: res}); // Set up the transport context
next(); }
next();
});
}); });
}; };
} }

View File

@ -1,4 +1,7 @@
var it = require('./util/it'); var it = require('./util/it');
var describe = require('./util/describe');
var Domain = require('domain');
var EventEmitter = require('events').EventEmitter;
describe('loopback', function() { describe('loopback', function() {
var nameCounter = 0; var nameCounter = 0;
@ -388,4 +391,72 @@ describe('loopback', function() {
}); });
}); });
}); });
describe.onServer('loopback.getCurrentContext', function() {
var runInOtherDomain;
var runnerInterval;
before(function setupRunInOtherDomain() {
var emitterInOtherDomain = new EventEmitter();
Domain.create().add(emitterInOtherDomain);
runInOtherDomain = function(fn) {
emitterInOtherDomain.once('run', fn);
};
runnerInterval = setInterval(function() {
emitterInOtherDomain.emit('run');
}, 10);
});
after(function tearDownRunInOtherDomain() {
clearInterval(runnerInterval);
});
// See the following two items for more details:
// https://github.com/strongloop/loopback/issues/809
// https://github.com/strongloop/loopback/pull/337#issuecomment-61680577
it('preserves callback domain', function(done) {
var app = loopback();
app.use(loopback.rest());
app.dataSource('db', { connector: 'memory' });
var TestModel = loopback.createModel({ name: 'TestModel' });
app.model(TestModel, { dataSource: 'db', public: true });
// function for remote method
TestModel.test = function(inst, cb) {
var tmpCtx = loopback.getCurrentContext();
if (tmpCtx) tmpCtx.set('data', 'a value stored in context');
if (process.domain) cb = process.domain.bind(cb); // IMPORTANT
runInOtherDomain(cb);
};
// remote method
TestModel.remoteMethod('test', {
accepts: { arg: 'inst', type: uniqueModelName },
returns: { root: true },
http: { path: '/test', verb: 'get' }
});
// after remote hook
TestModel.afterRemote('**', function(ctxx, inst, next) {
var tmpCtx = loopback.getCurrentContext();
if (tmpCtx) {
ctxx.result.data = tmpCtx.get('data');
}else {
ctxx.result.data = 'context not available';
}
next();
});
request(app)
.get('/TestModels/test')
.end(function(err, res) {
if (err) return done(err);
expect(res.body.data).to.equal('a value stored in context');
done();
});
});
});
}); });