Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

CLS and Promises #64

Closed
silverbp opened this issue Oct 9, 2015 · 19 comments
Closed

CLS and Promises #64

silverbp opened this issue Oct 9, 2015 · 19 comments

Comments

@silverbp
Copy link

silverbp commented Oct 9, 2015

Is there a way to patch this so CLS works inside the Promises without having to fork and patch the entire thing with cls-bluebird?

@analog-nico
Copy link
Member

Request-Promise uses just one promise internally which is instantiated when a request is made. That means you just need to call patchBluebird(...) of cls-bluebird before you execute your first request.

In comparison to the patch code of your fork you may even do the patching after you require Request-Promise:

var rp = require('request-promise');
var clsBluebird = require('cls-bluebird');

clsBluebird(...);

rp('http://google.com').then(...);

IMHO with this code there is no need to fork Request-Promise anymore. However, does this solution meet your expectation?

EDIT: The code can't work because Request-Promise requires a fresh prototype of Bluebird!

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

wouldn't this require that I have bluebird as a package as well, maybe it's a mis-understanding of how this works.
I can't patch bluebird cause I'm not using it in my own code.
inside of cls-bluebird, it's requiring bluebird.

I was under the assumption that npm modules are scoped to the library that adds it as a dependency.

If my assumption above is correct (it's probably not). How would I get to bluebird inside of request-promise to patch it without forking it?

I would love to not have to fork it.

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

I think mongoose went down the route of giving you the option of supplying your own promise library and since promises are built into es6, maybe it wouldn't be a bad idea to follow that convention on libraries that use promises (give people the option of supplying a promise library or maybe even checking to see if one exists globally (es6)).

@analog-nico
Copy link
Member

Ah yes, you are right! But anyways, to not having multiple versions of Bluebird laying around in your project Request-Promise intentionally has a loose version requirement for Bluebird (^2.3). If you already have installed Bluebird in your project then this version will be used by Request-Promise as well. That is NPM won't install another version of Bluebird anymore. Then the above code would actually work. However, as I write this I get the feeling this is not a save / clean solution.

I think CLS is a really important concept and should be treated accordingly. How about we add the following method to Request-Promise?

rp.bindCLS(/* ns */);

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

yes the above would work as well! thanks!

@analog-nico
Copy link
Member

I just realized that cls-bluebird should not work even for your fork because Request-Promise requires a fresh Bluebird prototype (require("bluebird/js/main/promise")() - see details here) and cls-bluebird therefore gets a different Bluebird prototype (require('bluebird')).

Could you double check that?

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

It works, cls-bluebird has bluebird as a peerdependency so it's looking for it in the parent project. I was wondering that too, till I looked in the package.json

The fork is currently working for me.

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

Oh, I don't know about the fresh bluebird prototype though, it passes my unit test :).. it has access to the CLS namespace in the success callback of the promise when hitting google.com.

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

the main bluebird entry point is this file (bluebird.js)

"use strict";
var old;
if (typeof Promise !== "undefined") old = Promise;
function noConflict() {
    try { if (Promise === bluebird) Promise = old; }
    catch (e) {}
    return bluebird;
}
var bluebird = require("./promise.js")();
bluebird.noConflict = noConflict;
module.exports = bluebird;

and it ultimately requires promise.js?

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

I'm not sure how what their saying even relates, it looks like bluebird stomps on the global Promise and you wouldn't want your blueprint of a dependency lib setting the 'old' property after a blueprint lib in a app set it, otherwise the behavior of calling 'noConflict' would have unexpected results. It might restore it to another bluebird promise instead of the old one..

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

so someone should do a pull request into cls-blueprint to not require blueprint.js, but instead promise.js like you guys are doing, to prevent the above.. or you could just replicate the code and change it :), it's not a lot of code.

@analog-nico
Copy link
Member

:D good point.

cls-bluebird could only also require promise.js if it afterwards returns the patched Bluebird prototype. If the user requires Bluebird himself - in any way - it will always get a different Bluebird prototype.

@analog-nico
Copy link
Member

I just checked Bluebird's code and find it really puzzling that your fork actually works. It shouldn't because the Bluebird prototype Request-Promise is using doesn't get patched. At least from what I can tell by reading all the relevant code. ;D

Anyway, I am now tending towards your suggestion to follow mongoose's strategy. Partly because issue #43 suggests some larger changes that result in being able to inject Bluebird - which might be CLS patched by the user - into Request-Promise.

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

give me a few minutes, I'll put a unit test together in my fork, the unit test I have working is in a different library.

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

I can't get it to fail now (sigh). I swear I just recently switched it and it failed, now it won't fail... So maybe the patch isn't doing anything.

@silverbp
Copy link
Author

silverbp commented Oct 9, 2015

I added a unit test anyway to that fork, that's similar to what we're doing where I swear it wasn't working, the only problem with my unit test is if you don't enable the patch, it still passes. So I don't know anymore.

@analog-nico
Copy link
Member

Working on the other issues was overdue anyway. I'll take all requirements - including CLS - and work on the next version of Request-Promise this weekend.

@analog-nico
Copy link
Member

I just released version 1.0.0 which includes the rp.bindCLS(/* ns */); function which we discussed. For details see the README section for that.

I am sorry, but I can only call this feature experimental. Since cls-bluebird is so quick and dirty it still misses a lot of use cases. Namely not allowing the user to bind the same namespace twice and allowing the user to bind multiple namespaces.

I am tracking cls-bluebird on VersionEye and will look into its code once a new version is released.

Thanks for getting this ball rolling @silverbp !

@analog-nico
Copy link
Member

Hi @silverbp , I just released request-promise@4.0.0 which drops CLS support due to numerous complaints about the way I added its support. However, I came up with an alternative solution which should be very easy for you to migrate to: https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage

I hope this introduces no trouble for you! And let me know if the migration doesn't work in one way or another so I can help.

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

No branches or pull requests

2 participants