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

Avoid an indefinite recursion that grows the call stack when reporting the current state fails #480

Merged
2 commits merged into from Nov 3, 2017

Conversation

pcarranzav
Copy link
Contributor

@pcarranzav pcarranzav commented Jul 27, 2017

We used to have a recursion based on Promises and Promise.delay, which caused the promise never to resolve
so eventually the stack would be exhausted.

This fixes it by using a simpler way to check if reporting the state is in progress and using a setImmediate to
call applyState outside of the Promise chain.

Change-Type: patch
Signed-off-by: Pablo Carranza Velez pablo@resin.io

Connects to https://github.com/resin-io/hq/issues/971

Front logo Front conversations

@pcarranzav pcarranzav requested review from imrehg and Page- July 27, 2017 00:02
@Page-
Copy link
Contributor

Page- commented Jul 27, 2017

@pcarranzav I'd be surprised if that setImmediate fixed it, as the promise handlers will be called in a setImmediate (or similar async construct) meaning they start with a fresh stack already

@pcarranzav
Copy link
Contributor Author

pcarranzav commented Jul 27, 2017

@Page- this seems to be the only possible culprit - maybe related to petkaantonov/bluebird#1326 - my expectation is that this promise chain will be resolved and a new one will be created, clearing the stack

@pcarranzav
Copy link
Contributor Author

(Still not sure though, investigating)

@pcarranzav
Copy link
Contributor Author

I just ran this, left it running overnight, and woke up to an "out of memory" error:

a = Promise.resolve()
b = -> Promise.resolve()
c = -> Promise.join(a, b(), -> throw new Error()).catch( -> Promise.delay(0.00001)).finally(-> c())
d = c()

(on a resin/amd64-node:6.5-slim container)

@pcarranzav
Copy link
Contributor Author

@Page- there seems to be a few issues in bluebird relating to the stack limit being reached in similar loops, which makes me think there must be some scenario in which such an async construct doesn't work as expected

@pcarranzav
Copy link
Contributor Author

pcarranzav commented Jul 28, 2017

Also @Page-, as per this comment, storing the returned promise is an antipattern that can cause a bit of a memory bloat (it should be cleared after 4 interactions, but still...).
I'm growing more confident that this change will solve the issue.

@pcarranzav
Copy link
Contributor Author

pcarranzav commented Aug 17, 2017

I wonder if this might also fix #485 - is it possible that the internal Promise bitfield changes asynchronously, so there is a non-zero time where applyState has returned and applyPromise.isPending() still returns true?
What do you think @Page- ?

Update: actually, no. That issue was something else.

…g the current state fails

We used to have a recursion based on Promises and Promise.delay, which caused the promise never to resolve
so eventually the stack would be exhausted.

This fixes it by using a simpler way to check if reporting the state is in progress and using a setImmediate to
call applyState outside of the Promise chain.

Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
@ghost
Copy link

ghost commented Nov 3, 2017

@pcarranzav, status checks have failed for this PR. Please make appropriate changes and recommit.

@ghost ghost merged commit bb350ec into master Nov 3, 2017
@ghost ghost deleted the fix-recursive-applystate branch November 3, 2017 03:59
This pull request was closed.
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

Successfully merging this pull request may close these issues.

None yet

2 participants