-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MongoDB - loopback.getCurrentContext() return null #885
Conversation
loopback.getCurrentContext() return null after MongoDB call returns. wrap up @Ichenay's patch lchenay@f075c79
Can one of the admins verify this patch? To accept patch and trigger a build add comment ".ok\W+to\W+test." |
@slnode ok to test |
@projectxmaker thank you for the patch. Could you please add a unit-test verifying the fix? The test should fail without the changes proposed here and it should pass once the patch is applied. Look at the tests in mongodb driver (mongodb/node-mongodb-native@66f8987) for inspiration. For the loopback test, you should probably create a custom model method that calls domains and then call this method from the test via the REST API. I put together a sample code to show you what I mean: var Domain = require('domain');
var Product = loopback.createModel('Product', { base: 'Model' });
Product.check = function(next) {
Domain.create().run(next);
};
Product.remoteMethod('check', { /*...TODO... */ });
// TODO: add afterRemote hook that will verify whether the context is set
app.model(Product, { dataSource: null });
request(app).get('/products/check')
// etc. @raymondfeng since you are the author of the context middleware, could you please review this patch too? |
@bajtos plz help me to verify this test file below even when the patch is not applied, and datasource is either mongodb or memory, the result returned from this test is OK. I don't know why, I missed something ??? O.o var loopback = require('loopback');
var request = require('supertest');
var Domain = require('domain');
var assert = require('assert');
describe('check loopback.getCurrentContext', function() {
var app = loopback();
before(function(){
var called = false;
app.use(loopback.rest());
app.dataSource('db', { connector: 'memory' });
app.dataSource('mongox', {
"host": "localhost",
"port": 27017,
"database": "api",
"username": "root",
"password": "123456",
"name": "mongodb",
"connector": "mongodb"
});
var TestModel = loopback.createModel({name: 'TestModel', properties: {name: String}, options: { base: 'Model'}});
app.model(TestModel, {dataSource: "db", public: true});
// before remote hook
TestModel.beforeRemote('**', function(remotingCtx, unused, next) {
//Domain.create().run(function(){
tmpCtx = loopback.getCurrentContext();
if (tmpCtx) tmpCtx.set('data', 'test');
next();
//});
});
// function
TestModel.test = function(inst, cb) {
called = true;
cb();
};
// remote method
TestModel.remoteMethod('test', {
accepts: {arg: 'inst', type: 'TestModel'},
returns: {root: true},
http: {path: '/test', verb: 'get'}
});
// after remote hook
TestModel.afterRemote('**', function(ctxx, inst, next){
ctxx.result.called = called;
tmpCtx = loopback.getCurrentContext();
if (tmpCtx) {
ctxx.result.data = tmpCtx.get('data');
}else {
ctxx.result.data = "";
}
next();
});
});
it('should fail without the patch and it should pass once the patch is applied', function(done) {
request(app)
.get('/TestModels/test')
.end(function(err, res) {
if (err) return done(err);
assert.equal(res.body.called, true);
assert.equal(res.body.data, 'test');
done();
});
});
}); |
@bajtos hello, are you still with me on this issue ? |
Uff, this was tricky. Here is the relevant part of the code that works for me: var otherDomain = Domain.create();
otherDomain.uid = 'other';
var emitterInOtherDomain = new EventEmitter();
otherDomain.add(emitterInOtherDomain);
setInterval(function() { emitterInOtherDomain.emit('run'); }, 10);
function runInOtherDomain(fn) {
emitterInOtherDomain.once('run', fn);
}
TestModel.test = function(inst, cb) {
tmpCtx = loopback.getCurrentContext();
if (tmpCtx) tmpCtx.set('data', 'test');
called = true;
runInOtherDomain(cb);
}; To use this in your test, you should clear the interval after a test is done. 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);
}); |
"works for me" means that the test fails against the current loopback version. I did not check whether the test passes with your patch applied. |
One more thing: My example above will most likely fail even with the patch in place. Here is a version that is more likely to pass: TestModel.test = function(inst, cb) {
tmpCtx = loopback.getCurrentContext();
if (tmpCtx) tmpCtx.set('data', 'test');
called = true;
if (process.domain) cb = proces.domain.bind(cb); // IMPORTANT
runInOtherDomain(cb);
}; |
@bajtos thanks, following is final test script that failed without patch and worked with patch. var loopback = require('loopback');
var request = require('supertest');
var Domain = require('domain');
var assert = require('assert');
var EventEmitter = require("events").EventEmitter;
describe('check loopback.getCurrentContext', function() {
var app = loopback();
var runInOtherDomain;
var runnerInterval;
before(function(){
var called = false;
app.use(loopback.rest());
app.dataSource('db', { connector: 'memory' });
app.dataSource('mongox', {
"host": "localhost",
"port": 27017,
"database": "api",
"username": "root",
"password": "123456",
"name": "mongodb",
"connector": "mongodb"
});
var TestModel = loopback.createModel({name: 'TestModel', properties: {name: String}, options: { base: 'Model'}});
app.model(TestModel, {dataSource: "db", public: true});
var emitterInOtherDomain = new EventEmitter();
Domain.create().add(emitterInOtherDomain);
runInOtherDomain = function(fn) {
emitterInOtherDomain.once('run', fn);
}
runnerInterval = setInterval(function() { emitterInOtherDomain.emit('run'); }, 10);
// function for remote method
TestModel.test = function(inst, cb) {
tmpCtx = loopback.getCurrentContext();
if (tmpCtx) tmpCtx.set('data', 'test');
called = true;
if (process.domain) cb = process.domain.bind(cb); // IMPORTANT
runInOtherDomain(cb);
};
// remote method
TestModel.remoteMethod('test', {
accepts: {arg: 'inst', type: 'TestModel'},
returns: {root: true},
http: {path: '/test', verb: 'get'}
});
// after remote hook
TestModel.afterRemote('**', function(ctxx, inst, next){
ctxx.result.called = called;
tmpCtx = loopback.getCurrentContext();
if (tmpCtx) {
ctxx.result.data = tmpCtx.get('data');
}else {
ctxx.result.data = "";
}
next();
});
});
after(function tearDownRunInOtherDomain() {
clearInterval(runnerInterval);
});
it('should fail without the patch and it should pass once the patch is applied', function(done) {
request(app)
.get('/TestModels/test')
.end(function(err, res) {
if (err) return done(err);
assert.equal(res.body.called, true);
assert.equal(res.body.data, 'test');
done();
});
});
}); |
@projectxmaker please include the test in the code of this pull request and remove the definition of unused |
test script for issue: “MongoDB - loopback.getCurrentContext() return null” #885
|
|
||
// after remote hook | ||
TestModel.afterRemote('**', function(ctxx, inst, next){ | ||
ctxx.result.called = called; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is redundant. If the method was not called then tmpCtx.get('data')
returns undefined.
Please remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
The code is not passing the linter, run |
I'm keen on seeing this patch merged. I spent 5 minutes to fix the few minor problems with @projectxmaker's work, and now the tests pass. What's the procedure to move this forward? |
@doublemarked 👍 sorry, I was very busy last week, thanks for your fix ^^ |
:) No worries, @projectxmaker! |
Excuse my late reply, I was on holiday. Please agree which version should be moved forward. If it's the version from @doublemarked, then please open a new pull request. Also change the name of the test to describe the scenario being tested (e.g. "preserves domain across async calls"). |
@projectxmaker - let me know how you prefer to proceed |
@doublemarked let keep giving a hand in fixing the issue of the test file if you have time ^^ @bajtos can you give me more details about your following comment, I don't get it O.o
|
To speed the things up, I have made the final amendments myself and landed the patch via 989abf6:
Thank you for the contribution! @doublemarked @projectxmaker could you please verify that the bug is fixed, before I make a release? Just run |
cool, I tested and it works properly ;) |
Thanks, I have released the fix as |
Hey guys - looks great for me as well. Thank you for the release! |
Please see #1080 - domains are tricky. |
Hi @bajtos , I'm facing this issue on the nearly latest version. Bellow is my
I've used a middleware to save current logged user data into context but it ( Bellow is my code,
Can you please have a look ? Have I done something wrong ? Thanks. |
Have just the same problem with getCurrentContext. It returns null |
loopback.getCurrentContext() return null after MongoDB call returns.
wrap up @Ichenay's patch lchenay@f075c79 (see this comment for more details: #337 (comment))
Fix #809