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

Add support for removing cancelled bluebird3 promises from the cache. #97

Conversation

Page-
Copy link
Contributor

@Page- Page- commented Aug 3, 2018

When a bluebird3 promise is cancelled it doesn't call any success/failure handles which means that it appears to be permanently waiting in terms of the cache and will be given out to every subsequent call.
This is a problem as when you try to subscribe to the returned, cancelled, promise it rejects with a CancellationError so we end up with a poisoned cache. This PR checks if the promise can attach cancellation handlers and if so we attach the onFailure handler to clean up in case of cancellation

@Page- Page- force-pushed the remove-cancelled-bluebird3-promises branch from 19bc67d to 82489ca Compare August 3, 2018 01:31
Copy link
Owner

@medikoo medikoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason tests failed in some engines on Windows.

Maybe it's issue of some race condition in setTimeout handling (I would increase success resolution timeout to 500)

ext/promise.js Outdated

// If `_attachCancellationCallback` is a function we attach to it to remove cancelled
// promises from the cache.
if (typeof promise._attachCancellationCallback === "function") {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'll be nicer to rely on public API, so promise.finally (that way we'll also support also any other implementation that do cancellation)>

For that we can add promise.finally(function () { nextTick(onFailure); }) to then mode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's much better - for some reason I thought finally didn't get called on cancel

@Page- Page- force-pushed the remove-cancelled-bluebird3-promises branch from 6c99df9 to caf2086 Compare August 4, 2018 01:06
@Page-
Copy link
Contributor Author

Page- commented Aug 4, 2018

The lint is now failing due to an update in https://github.com/medikoo/eslint-config-medikoo - how would you like the lint cases fixed?

@medikoo
Copy link
Owner

medikoo commented Aug 4, 2018

The lint is now failing due to an update in https://github.com/medikoo/eslint-config-medikoo - how would you like the lint cases fixed?

I've fixed this in master. Issue was related to recent eslint upgrade (v4 -> v5). Therefore merge, and lint should be ok

@Page- Page- force-pushed the remove-cancelled-bluebird3-promises branch from 1be46de to 16c9b70 Compare August 5, 2018 20:03
@Page-
Copy link
Contributor Author

Page- commented Aug 6, 2018

I picked up the master changes and all the tests look good now

@medikoo medikoo merged commit b4b018d into medikoo:master Aug 6, 2018
@medikoo
Copy link
Owner

medikoo commented Aug 6, 2018

Thank you, published with v0.4.13

@Page-
Copy link
Contributor Author

Page- commented Aug 7, 2018

Awesome, thanks!

@Page- Page- deleted the remove-cancelled-bluebird3-promises branch August 7, 2018 15:26
);
// If `finally` is a function we attach to it to remove cancelled promises.
if (typeof promise.finally === "function") {
promise.finally(nextTickFailure);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Page- @medikoo won't this always call onFailure and always remove it from the cache? It looks like .finally is called regardless http://bluebirdjs.com/docs/api/finally.html

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will, but first what's attached is callback to then, and that one will be first invoked in success case. Fact that nextTickFailure will be invoked afterwards in all cases does no harm, it'll just exit here:

if (!waiting[id]) return; // Deleted from cache (or succeed in case of finally)

Still, even If there's some promise library which in given scenario:

promise.then(callback1)
promise.finally(callback2)

will call callback2 before callback1, it'll crash with meaningful error here:

memoizee/ext/promise.js

Lines 44 to 49 in 2b1f941

throw new Error(
"Memoizee error: Detected unordered then|done & finally resolution, which " +
"in turn makes proper detection of success/failure impossible (when in " +
"'done:finally' mode)\n" +
"Consider to rely on 'then' or 'done' mode instead."
);

So situation will be properly exposed

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks for the explanation.

The only case I see that could potentially produce a false positive is if one of nextTick's implementations doesn't guarantee in-order execution of the scheduled functions.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only case I see that could potentially produce a false positive is if one of nextTick's implementations doesn't guarantee in-order execution of the scheduled functions.

I'm pretty sure order is guaranteed in all of them, otherwise there will be dragons :)

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

Successfully merging this pull request may close these issues.

3 participants