-
Notifications
You must be signed in to change notification settings - Fork 19
Follow promises across resolve #40
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
base: master
Are you sure you want to change the base?
Follow promises across resolve #40
Conversation
|
I will try and get this reviewed soon. My immediate thoughts are:
In any case, I have been thinking about using the If you could split it up that would help a lot. |
|
Hi, thanks for taking a look :) Yep, it's definitely slower right now. However for my use case the improved debug info is more than worth it. Most of the slowness seems to be in keeping the It definitely does solve #34. I've tested the example from the async-test repository with an increased stackTraceLimit. I also added my own similar test case to my fork. I've just written some pretty printing logic which should help to demonstrate what's happening if you run it. I'll also try to split it up into a few more commits. Do you want separate PRs for the editorconfig and |
e44c237 to
47108d5
Compare
This stops the tests from breaking with Node.js updates.
47108d5 to
a4e78d8
Compare
|
Hi again! I've pushed up some new changes. Fix a memory leak that exists on masterUnfortunately keeping references to CallSite objects causes a huge memory leak. I copy the interesting fields into a new object to work around this. Specifically if we keep a CallSite which refers to a promise then we have created a cyclic dependency. Node will not call asyncDestroy for the promise until it is garbage collect. Because we are referencing the promise through the traces map through a CallSite we have a leak. Unfortunately this naive solution makes it about 2.5x slower. Significantly more efficient tracking of async context / promiseResolve graphThe new code for tracking Rebased everything again to try to make a comprehensible and reviewable list of commits.Please let me know when you start reviewing this. At that point I'll stop rebasing so you can track any additions separately. |
…original This stops a memory leak. The CallSite keeps a reference to Promise objects. This stops the Promise from being garbage collected, which stops asyncDestroy from being called.
- For each non-destroyed async context we store a `Trace` object in the global `traces` map. - A trace object contains an array of `NamedStack` objects. This is simply a pair of `asyncId` and `frames`. - Whenever a new async context is created we ask the trigger Trace to copy its `stacks` into the newly created Trace. - The final long stack trace is assembled only if needed. This means tracking `executionScopeInits` is not necessary because we can do the stack trace deduplication later. - Moved `equalCallSites` next to its caller, `extendFrames` - `equalCallSites` treats anonymous stack frames as equal
Whenever a promise resolves we copy the trigger `Trace.stacks` into the current async context's `Trace`. We also recursively copy it into all related Traces. This means any Error stacks that are extended from this point on will contain the new frames. Note this leaks lots of memory, see the next commit for some limits.
a4e78d8 to
1069810
Compare
Edited 2018-02-20 after rebasing.
Edited 2018-02-23 after fixing memory leak and rebasing.
There are four distinct changes in this PR. I'm happy to reraise them as separate PRs if that's more convenient.
This is ready for review, but still early days. I intend to try this out on some of our real services for a while. I'll let you know how that goes.I've been running this in production for about a week now. The only serious issue was a memory leak which has been fixed.
Thanks for looking :)
Add .editorconfig and .eslintrc
EditorConfig is awesome: http://EditorConfig.org
Fix tests on newer Node.js
The tests didn't pass for me on Node.js 9.5.0. I've modified
test.jsto strip all Node.js lines from the stack frames. This isn't ideal because it throws away some useful data. However the tests do now pass on Node 8 and 9 :)Fix memory leak
Unfortunately keeping references to
CallSiteobjects causes a huge memory leak. I copy the interesting fields into a new object to work around this.Specifically if we keep a
CallSitewhich refers to a promise then we have created a cyclic dependency. Node will not callasyncDestroyfor the promise until it is garbage collect. Because we are referencing the promise through thetracesmap through aCallSitewe have a leak.Follow promises across resolve
To fix issue #34 I've refactored
trace.jsto store trace data in aTraceobject and only join stack frames when the stack is being printed.A
Traceobject is created for eachinitcallback and saved in a global map. This is linked to the trace object created for thetriggerAsyncId. For non-promises this results in a linked list of objects which joins to an equivalent list of stack frames.For promises we make use of the
promiseResolvecallback to linkTraceobjects. This results in a graph structure. By the time the stack trace is being printed we have a lot more stack frames.Benchmark
On master
With the copying of
CallSitesto fix the memory leak (commit f34d095)With all the new code
With only the new promise tracking code (
CallSitecopying disabled)