strongloop/loopback

Context doesn't work with Node 4.3.1

Closed this issue · 7 comments

Hello,

we wanted to update our servers to Node v4.3.1 but unfortunately we have a problem with loopback context. We are using session manager for express and init the session when setContext is run:

// Configure to set current customer or employee                                                                                                                   
app.use(function setContext(req, res, next) {                                                                                                                      
  var loopbackContext = loopback.getCurrentContext();                                                                                                              
  var session = req.session;                                                                                                                                       
  session.sessionID = req.sessionID;                                                                                                                               
  loopbackContext.set('session', session);                                                                                                                                                                                                                                          

  if (req.accessToken) {                                                                                                                                           
    async.parallel({                                                                                                                                               
      customer: function (cb) {                                                                                                                                    
        app.models.Customer.findById(req.accessToken.userId, function (err, customer) {                                                                            
          cb(null, customer);                                                                                                                                      
        });                                                                                                                                                        
      },                                                                                                                                                           
      employee: function (cb) {                                                                                                                                    
        app.models.Employee.findById(req.accessToken.userId, function (err, employee) {                                                                            
          cb(null, employee);                                                                                                                                      
        });                                                                                                                                                        
      }                                                                                                                                                            
    }, function (err, results) {                                                                                                                                   
      if (loopbackContext) {                                                                                                                                       
        if (results.customer)                                                                                                                                      
          loopbackContext.set('customer', results.customer);                                                                                                       
        if (results.employee)                                                                                                                                      
          loopbackContext.set('employee', results.employee);                                                                                                       
      }                                                                                                                                                            
      next();                                                                                                                                                      
    });                                                                                                                                                            
  } else {                                                                                                                                                         
    next();                                                                                                                                                        
  }                                                                                                                                                                
});                

Inside of this function the loopbackContext.get('session') works without problem. The problem is, that when we use the context in a remote method, it doesn't work, as loopbackContext.get('session') - undefined:

var ctx = loopback.getCurrentContext();
var session = ctx && ctx.get('session');                  <===== undefined

Any clues?

If we change:
loopbackContext.set('session', session); >>>> loopbackContext.test = {session: session};

Then we can retrieve the session without any problem:

loopbackContext.test.session

Is there a problem in loopback, that this "get" method of context is loosing scope?

Hi, it is being said that loopback.getCurrentContext() is pretty much deprecated at this point.
I had my own odyssey with bumping my head against it, and in the end I completely replaced all usage of getCurrentContext() with the proposed alternative solution of injecting the remote context via the options argument (see #1495).

This is working without any problems so far and I think others are using it as well in place of getCurrentContext(). So you could give it a try and see if you can make it work for your usecase, and avoid all the troubles that lie dormant within getCurrentContext() and the CLS.

Just my 0.02$ 😉

loay commented

Thanks @drywolf
@ekussberg does the previous comment by @drywolf fix your issue.
You can have a further look at this case here: #1961
Thanks.

What we are using is exactly what is written in the docs:
https://docs.strongloop.com/display/public/LB/Using+current+context

But now i have redefined the part in server.js to:

// Configure to set current customer or employee
function injectOnLoad(ctx, next) {
  // Create foodo object in context
  ctx.foodo = {};
  // Add session to context
  var session = ctx.req.session;
  session.sessionID = ctx.req.sessionID;
  ctx.foodo.session = session;
  if (ctx.req.accessToken) {
    async.parallel({
      customer: function (cb) {
        app.models.Customer.findById(ctx.req.accessToken.userId, function (err, customer) {
          cb(null, customer);
        });
      },
      employee: function (cb) {
        app.models.Employee.findById(ctx.req.accessToken.userId, function (err, employee) {
          cb(null, employee);
        });
      }
    }, function (err, results) {
      if (ctx) {
        if (results.customer)
          ctx.foodo.customer = results.customer;
        if (results.employee)
          ctx.foodo.employee = results.employee;
      }
      next();
    });
  } else {
    next();
  }
}
app.remotes().before('*.*', injectOnLoad);
app.remotes().before('*.prototype.*', function (ctx, instance, next) {
  injectOnLoad(ctx, next);
});

But how now i can get the "ctx" inside of the remote method or other helper classes?

@ekussberg
If you are trying to implement the approach suggested in #1495 then you are missing the most essential parts. You need to patch the remote method parameter lists to include an additional "options" parameter. Then in the relevant remotes().before(...) handlers inject the context into the options object that will be passed to the remote methods.

This means that you also need to include this parameter in the remote method definition where you want to use it. You should end up having a signature like function (...method-args..., options, response_cb).

In the options argument you will receive the context that you injected.

loay commented

Hi @ekussberg @drywolf
is this issue resolved?

Hello, we have landed & released an official solution for injecting context via "options" arg, see #1495 and the related pull requests.

There is also a parallel work done by @josieusa where loopback-context was upgraded to use cls-hooked under the hood. Feel free to try the new version loopback-context@3.0.0. If you run into issues, then please report them in loopback-context's issue tracker.

I am closing this issue as it's no longer actionable for us.