Skip to content
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

Lost context inside Mongoose query callback function #58

Open
airicyu opened this issue Feb 11, 2016 · 5 comments
Open

Lost context inside Mongoose query callback function #58

airicyu opened this issue Feb 11, 2016 · 5 comments

Comments

@airicyu
Copy link

airicyu commented Feb 11, 2016

Using CLS with Mongoose is broken inside query callback function. The context is lost.

sample:

console.log("### outside mongoose query", ns.get("foo"));
SomeMongooseModel.find(query, function(err, obj){
   console.log("### inside mongoose query", ns.get("foo"));
});

problem:
The problem is that the outside query code can get the variable from CLS namespace, while the inside query callback function cannot get the variable. It apparently lost the context.

temp-solution:
I find that explicitly call namespace bind to wrap the callback function can be workaround:

console.log("### outside mongoose query", ns.get("foo"));
SomeMongooseModel.find(query, ns.bind(function(err, obj){
   console.log("### inside mongoose query", ns.get("foo"));
}));

However, this temp-solution require explicit call to wrap the callback function which is ugly and not easy to maintain in future.

supplymentary information:
Node version: v4.2.4
CLS version: 3.1.6
Mongoose version: 4.4.3

Are there any cleaner solution for this issue?

@Qard
Copy link
Collaborator

Qard commented Feb 12, 2016

It's a queueing problem. You get that with user-mode queueing/pooling mechanisms. You'll need to patch the function before it enters the queue/pool.

Try this:

var addQueue = mongoose.Collection.prototype.addQueue
mongoose.Collection.prototype.addQueue = function (name, args) {
  var last = args[args.length - 1]
  if (typeof last === 'function') {
    args[args.length - 1] = ns.bind(last)
  }
  return addQueue.call(this, name, args)
}

@airicyu
Copy link
Author

airicyu commented Feb 12, 2016

Hi Qard, your fix is not work. I checked that the addQueue function has never been called in my code at runtime.

@airicyu
Copy link
Author

airicyu commented Feb 12, 2016

Finally make the workaround work.

var find = mongoose.Query.prototype.find;
mongoose.Query.prototype.find = function () {
  var args = arguments;
  var last = args[args.length - 1];
  if (typeof last === 'function') {
    args[args.length - 1] = namespace.bind(last);
  }  
  return find.apply(this, args);
}

By using some code like this, I can wrap the "find" method to get the CLS work inside my callback function.

However, it is still a kind of ugly workaround which I explicitly inject into. I still hope that CLS would have a better solution for similar use cases in some later release. Thanks!

@Qard
Copy link
Collaborator

Qard commented Feb 12, 2016

CLS itself only focuses on supporting node core. There are various plugins to patch some userland modules which break due to queueing/pooling: https://www.npmjs.com/browse/keyword/continuation-local-storage

Sadly, there's not really a reliable way to automatically propagate the context.

@cwienands
Copy link

cwienands commented Dec 14, 2017

I just ran into the same issue. I resolved it simply by switching from callback functions to arrow functions. I.e. from
SomeMongooseModel.find(query, function(err, obj){ console.log("### inside mongoose query", ns.get("foo")); });
to
SomeMongooseModel.find(query, (err, obj) => { console.log("### inside mongoose query", ns.get("foo")); });
Note: No idea why line breaks in the code blocks are ignored. Sorry!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants