request / request-promise

The simplified HTTP request client 'request' with Promise support. Powered by Bluebird.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CLS and Promises

silverbp opened this issue · comments

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?

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!

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.

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)).

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 */);

yes the above would work as well! thanks!

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?

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.

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.

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?

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..

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.

: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.

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.

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.

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.

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.

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.

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 !

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.