-
Notifications
You must be signed in to change notification settings - Fork 30k
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
Missing async callstacks on setTimeout #11370
Comments
@nodejs/v8-inspector does anyone know what hooks would have to be implemented? I will gladly take the hooks and put them in the correct places in the timers code once I know what they are. XD |
ping @nodejs/v8-inspector |
Hmmm, that requires us to make some sort of ID for each timer scheduling by the looks of it? Maybe we could re-use the async_id once async_hooks lands. Also, we'll have to add a lot of jumping in-and-out of C++ I think. :/ |
It makes me wonder: can we extend async_hooks implementation to automatically call Considering that async_hook already has some C++ layer, it may be possible to avoid unnecessary jumping in-and-out of C++ if we can invoke Thoughts? Is this something to include in nodejs/diagnostics#29? |
This is a very big assumption. If we assume this, then all other long-stack-trace implementation that uses
The
Lets just track the |
@AndreasMadsen thank you for chiming in!
Well, I think once async_hooks becomes the standard for observing async operations, and more and more tooling start to rely on that (e.g. continuation-local-storage or APM agents), the ecosystem will have to integrate with async_hook. Similarly as they had to eventually integrate with
Yes! How awesome that will be! Maybe I am overly enthusiastic, but it seems to me that async_hooks is the only long-term solution to enable robust and reliable support for things like long-stack-traces or continuation-local-storage. The more benefits we can enable by async_hooks, the more likely module authors should be to integrate with this new API.
I admit my knowledge of Node.js internals is minimal, therefore I am happy to trust your judgment here.
From my point of view as Node.js user, I would prefer the opt-in/opt-out mechanism to be automatic:
BTW, a mechanism to detect whether the Node.js app is being debugged/inspected would be useful even outside of Node.js core. See e.g. petkaantonov/bluebird#1364, where we are discussing how to enable async stack traces when debugging bluebird in the inspector. It already works in Chrome DevTools, where Bluebird detects the inspector and switches to a different TaskQueue implementation (see petkaantonov/bluebird@d37d0ff). |
This makes sense to me.
The problem is that every module that does something special to the async stack (e.g. native binding, or ConnectionPool) need to integrate with I have a lot to say about this, but I will stop myself here. I have been teaching about async context for years at different events, it is just something that requires a very different mental model. |
This should be easier now that async_hooks has landed. I might be able to take a look next week. |
It would be great to add calls to V8 Inspector asyncTask* methods to corresponded async_hooks methods. Our general strategy to support async stacks in Chrome:
So we need to support node platform async primitives to get cool async stacks in DevTools. edit (@AndreasMadsen): fixed link. |
Hello, I went ahead and implemented async_hooks + asyncTask* integration here: #13870. Feedback is welcome! |
Implement a special async_hooks listener that forwards information about async tasks to V8Inspector asyncTask* API, thus enabling DevTools feature "async stack traces". The feature is enabled only on 64bit platforms due to a technical limitation of V8 Inspector: inspector uses a pointer as a task id, while async_hooks use 64bit numbers as ids. To avoid performance penalty of async_hooks when not debugging, the new listener is enabled only when the process enters a debug mode: - When the process is started with `--inspect` or `--inspect-brk`, the listener is enabled immediately and async stack traces lead all the way to the first tick of the event loop. - When the debug mode is enabled via SIGUSR1 or `_debugProcess()`, the listener is enabled together with the debugger. As a result, only async operations started after the signal was received will be correctly observed and reported to V8 Inspector. For example, a `setInterval()` called in the first tick of the event will not be shown in the async stack trace when the callback is invoked. This behaviour is consistent with Chrome DevTools. Last but not least, this commit fixes handling of InspectorAgent's internal property `enabled_` to ensure it's set back to `false` after the debugger is deactivated (typically via `process._debugEnd()`). Fixes: #11370 PR-URL: #13870 Reviewed-by: Timothy Gu <timothygu99@gmail.com> Reviewed-by: Anna Henningsen <anna@addaleax.net>
Implement a special async_hooks listener that forwards information about async tasks to V8Inspector asyncTask* API, thus enabling DevTools feature "async stack traces". The feature is enabled only on 64bit platforms due to a technical limitation of V8 Inspector: inspector uses a pointer as a task id, while async_hooks use 64bit numbers as ids. To avoid performance penalty of async_hooks when not debugging, the new listener is enabled only when the process enters a debug mode: - When the process is started with `--inspect` or `--inspect-brk`, the listener is enabled immediately and async stack traces lead all the way to the first tick of the event loop. - When the debug mode is enabled via SIGUSR1 or `_debugProcess()`, the listener is enabled together with the debugger. As a result, only async operations started after the signal was received will be correctly observed and reported to V8 Inspector. For example, a `setInterval()` called in the first tick of the event will not be shown in the async stack trace when the callback is invoked. This behaviour is consistent with Chrome DevTools. Last but not least, this commit fixes handling of InspectorAgent's internal property `enabled_` to ensure it's set back to `false` after the debugger is deactivated (typically via `process._debugEnd()`). Fixes: #11370 PR-URL: #13870 Reviewed-by: Timothy Gu <timothygu99@gmail.com> Reviewed-by: Anna Henningsen <anna@addaleax.net>
Implement a special async_hooks listener that forwards information about async tasks to V8Inspector asyncTask* API, thus enabling DevTools feature "async stack traces". The feature is enabled only on 64bit platforms due to a technical limitation of V8 Inspector: inspector uses a pointer as a task id, while async_hooks use 64bit numbers as ids. To avoid performance penalty of async_hooks when not debugging, the new listener is enabled only when the process enters a debug mode: - When the process is started with `--inspect` or `--inspect-brk`, the listener is enabled immediately and async stack traces lead all the way to the first tick of the event loop. - When the debug mode is enabled via SIGUSR1 or `_debugProcess()`, the listener is enabled together with the debugger. As a result, only async operations started after the signal was received will be correctly observed and reported to V8 Inspector. For example, a `setInterval()` called in the first tick of the event will not be shown in the async stack trace when the callback is invoked. This behaviour is consistent with Chrome DevTools. Last but not least, this commit fixes handling of InspectorAgent's internal property `enabled_` to ensure it's set back to `false` after the debugger is deactivated (typically via `process._debugEnd()`). Fixes: #11370 PR-URL: #13870 Reviewed-by: Timothy Gu <timothygu99@gmail.com> Reviewed-by: Anna Henningsen <anna@addaleax.net>
When debugging Chrome, you can have code like
and if you pause in the timeout handler and enable async callstacks in Chrome DevTools, you'll see the callstack that lead to calling setTimeout:
But if I debug the same code in Node using the inspector protocol, I don't see async callstacks in this case. But I do see async callstacks for Promises. So it must have something to do with Node's timer implementation. Is there any way that it could surface async callstacks too?
The text was updated successfully, but these errors were encountered: