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

loopback.getCurrentContext() return null after MongoDB call returns #809

Closed
bluestaralone opened this Issue Nov 14, 2014 · 9 comments

Comments

Projects
None yet
6 participants
@bluestaralone

bluestaralone commented Nov 14, 2014

A follow-up for #766.

I tested on https://github.com/strongloop/loopback-example-app

Step to create bug like this:

  1. run npm install strongloop/loopback
  2. Add the code below into Customer.js
  3. Add debug codes
  4. Run app
  5. Go to explorer page and make a request GET /Customers
  6. Go to explorer page and Login to get AccessToken
  7. Go to explorer page and set AccessToken to header in Explorer page
  8. Go to explorer page and make a request GET /Customers
  9. Check console log

My code:

var loopback = require('loopback');

module.exports = function(Customer) {

  Customer.beforeRemote('**', function(remotingCtx, unused, next) {
    loopbackCtx = loopback.getCurrentContext();
    console.log("beforeRemote", loopbackCtx);
    loopbackCtx.modelData = 'aaaaaaaaaaaaaaa';
    next();
  });

  Customer.beforeSave =  function(next, customer) {
    loopbackCtx = loopback.getCurrentContext();
    console.log("beforeSave", loopbackCtx);
    next();
  };
};

and my log:

supervisor running without clustering (unsupervised)
Browse your REST API at http://localhost:3000/explorer
Web server listening at: http://localhost:3000/
beforeSave null
beforeSave null
beforeSave null
beforeSave null
beforeRemote { name: 'loopback',
  active: { accessToken: undefined },
  _set: [ null, { accessToken: undefined } ],
  id: 
   { create: [Function],
     flags: 15,
     before: [Function],
     after: [Function],
     error: [Function],
     uid: 1,
     data: null } }
beforeRemote null
@bluestaralone

This comment has been minimized.

bluestaralone commented Nov 18, 2014

@bajtos : we are waiting for your response. Please help us ? thanks.
@raymondfeng : If baitos is too busy, can you help us ?

@raymondfeng

This comment has been minimized.

Member

raymondfeng commented Nov 18, 2014

I can see the accessToken:

beforeRemote { name: 'loopback',

  active: 
   { accessToken: 
      { id: 'V6RJPkSe9RhvxJ8QfBpTuYXuNFeZsGZvodLzzpSQ5cY5WQTnJe1BSVYVUxIW1nKD',
        ttl: 1209600,
        created: Mon Nov 17 2014 21:38:32 GMT-0800 (PST),
        userId: '84' } },
  _set: [ null ],
@glesage

This comment has been minimized.

glesage commented Nov 25, 2014

I also get null when calling loopback.getCurrentContext(); from inside Model.beforeSave() or others (anything other than Model.beforeRemote()) basically...

But I may be doing something wrong, waiting on #761 (:

@bajtos

This comment has been minimized.

Member

bajtos commented Nov 27, 2014

First of all, you have to call .set and .get to write/read context properties.

// correct
loopbackCtx.set('modelData', 'aaaaaaaaaaaaaaa');

// wrong
loopbackCtx.modelData = 'aaaaaaaaaaaaaaa';

As for loopback.getCurrentContext() returning null, I'll try to find time to investigate it little bit more.

@bajtos

This comment has been minimized.

Member

bajtos commented Nov 28, 2014

Here is a full example that works for me:

var loopback = require('./');
var supertest = require('supertest');

var Product = loopback.createModel('Product', { name: String });

Product.beforeRemote('**', function(remotingCtx, unused, next) {
  ctx = loopback.getCurrentContext();
  if (ctx) ctx.set('data', 'test');
  next();
});

Product.beforeSave = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data:', ctx.get('data'));
  } else {
    console.log('ctx not set');
  }
  next();
};

var app = loopback();
app.dataSource('db', { connector: 'memory' });
app.model(Product, { dataSource: 'db' });

app.use(loopback.rest());

supertest(app).post('/products')
  .set('Content-Type', 'application/json')
  .send({ name: 'phone' })
  .expect(200)
  .end(function(){});

Output:

context data: test

Are you using MongoDB to store your data? This comment says that mongodb's driver breaks the context propagation. AFAIK there isn't any issue tracking this problem, feel free to open one in loopback-connector-mongodb. It would be even better if you could submit a patch based on the solution described in the linked comment.

@bajtos bajtos closed this Nov 28, 2014

@bajtos bajtos added the question label Nov 28, 2014

@projectxmaker

This comment has been minimized.

Contributor

projectxmaker commented Nov 30, 2014

@bajtos

I added your example code to /server/server.js as following

var loopback = require('loopback');
var boot = require('loopback-boot');

var app = module.exports = loopback();

var Product = loopback.createModel('Product', { name: String });

Product.beforeRemote('**', function(remotingCtx, unused, next) {
  ctx = loopback.getCurrentContext();
  if (ctx) ctx.set('data', 'test');
  next();
});

Product.afterInitialize = function() {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - afterInitialize :', ctx.get('data'));
  } else {
    console.log('context data - afterInitialize : ctx not set');
  }
};

Product.beforeValidate = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - beforeValidate :', ctx.get('data'));
  } else {
    console.log('context data - beforeValidate : ctx not set');
  }
  next();
};

Product.afterValidate = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - afterValidate:', ctx.get('data'));
  } else {
    console.log('context data - afterValidate: ctx not set');
  }
  next();
};

Product.beforeSave = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - beforeSave :', ctx.get('data'));
  } else {
    console.log('context data - beforeSave : ctx not set');
  }
  next();
};

Product.afterSave = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - afterSave:', ctx.get('data'));
  } else {
    console.log('context data - afterSave: ctx not set');
  }
  next();
};

Product.beforeCreate = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - beforeCreate:', ctx.get('data'));
  } else {
    console.log('context data - beforeCreate: ctx not set');
  }
  next();
};

Product.afterCreate = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - afterCreate:', ctx.get('data'));
  } else {
    console.log('context data - afterCreate: ctx not set');
  }
  next();
};

Product.beforeUpdate = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - beforeUpdate :', ctx.get('data'));
  } else {
    console.log('context data - beforeUpdate : ctx not set');
  }
  next();
};

Product.afterUpdate = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - afterUpdate:', ctx.get('data'));
  } else {
    console.log('context data - afterUpdate : ctx not set');
  }
  next();
};

Product.beforeDestroy = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - beforeDestroy :', ctx.get('data'));
  } else {
    console.log('context data - beforeDestroy : ctx not set');
  }
  next();
};

Product.afterDestroy = function(next, data) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - afterDestroy:', ctx.get('data'));
  } else {
    console.log('context data - afterDestroy: ctx not set');
  }
  next();
};

Product.afterRemote('**', function(remotingCtx, unused, next) {
  ctx = loopback.getCurrentContext();
  if (ctx) {
    console.log('context data - afterRemote:', ctx.get('data'));
  } else {
    console.log('context data - afterRemote: ctx not set');
  }
  next();
});


app.dataSource('db', { connector: 'memory' });
app.dataSource('mongox', {
    "host": "localhost",
    "port": 27017,
    "database": "api",
    "username": "root",
    "password": "123456",
    "name": "mongodb",
    "connector": "mongodb"
  });
app.model(Product, { dataSource: 'mongox' });
//app.model(Product, { dataSource: 'db' });

I did some test with your example and followings are testing result:

loopback v2.8.2
end-point: POST /products

with "memory" datasource

context data - afterInitialize : test
context data - beforeValidate : test
context data - afterValidate: test
context data - beforeCreate: test
context data - beforeSave : test
context data - afterSave: test
context data - afterCreate: test
context data - afterRemote test

with "mongox" datasource

context data - afterInitialize : test
context data - beforeValidate : test
context data - afterValidate: test
context data - beforeCreate: test
context data - beforeSave : test
context data - afterSave: ctx not set
context data - afterCreate: ctx not set
context data - afterRemote: ctx not set

testing result after applied the patch proposed by Ichenay at this comment, everything is fine now

context data - afterInitialize : test
context data - beforeValidate : test
context data - afterValidate: test
context data - beforeCreate: test
context data - beforeSave : test
context data - afterSave: test
context data - afterCreate: test
context data - afterRemote: test

so, it seems you need to consider and apply his patch soon ^^

@bajtos bajtos changed the title from Bug: loopback.getCurrentContext() return null when request with accessToken ? to loopback.getCurrentContext() return null after MongoDB call returns Dec 1, 2014

@bajtos bajtos added bug and removed question labels Dec 1, 2014

@bajtos

This comment has been minimized.

Member

bajtos commented Dec 1, 2014

@projectxmaker thank you for an extensive test. I have updated the title of this issue to reflect the problem.

Could you please wrap up @Ichenay's patch and send it as a proper pull request yourself?

@bajtos bajtos reopened this Dec 1, 2014

@projectxmaker

This comment has been minimized.

Contributor

projectxmaker commented Dec 1, 2014

@bajtos just created a pull request as you suggested #885

@bajtos

This comment has been minimized.

Member

bajtos commented Jan 7, 2015

The fix is available as of loopback@2.8.8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment