-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
async_hooks: add getActiveResources (prototype) #21453
Conversation
lib/async_hooks.js
Outdated
@@ -216,6 +246,7 @@ module.exports = { | |||
createHook, | |||
executionAsyncId, | |||
triggerAsyncId, | |||
GetActiveResources, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be getActiveResources
I would like to see a benchmark of this, that compares with the naive approach that uses |
@AndreasMadsen It's not actually possible to my understanding. I forgot to add this in (and so I will add it to the original post) but it is also a matter of handle access. The async_hooks approach breaks down because you cannot (or at least not without significant native addon trickery) to my knowledge keep handles around for access at any time. Doing so requires strong references because JS does not have full weakrefs and so the handles will never be GC'd. This solves that by bypassing the need to store in JS and just doing a full C++ resource fetch at request. |
Prototype of a new getActiveResources() API for async_hooks. Returns an object map of { <id>: <resource> }, and differs slightly from getActiveHandles(). Currently, it works for all async_hooks resources except nextTick-s, which are probably not useful to expose in this way.
7c63030
to
148ee61
Compare
Makes sense. Thanks for reminding me 👍 |
@@ -123,6 +124,35 @@ function createHook(fns) { | |||
} | |||
|
|||
|
|||
function getActiveResources() { | |||
const handles = process._getActiveHandles(); | |||
const reqs = process._getActiveRequests(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we... perhaps... move the implementations of these to an internal/*
so we can more easily deprecate the process._getActive*
variants later on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'll do that once it is a little more settled if people are ok this idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really against this, especially considering it is not easily implemented in userland. However, I still want to raise some concerns. And I'm wondering if there aren't better alternatives.
-
The resource objects are essentially completely undocumented. And we properly don't want to ever document them. So we really have to ask the question, will this really advance the story of making
_getActiveHandles()
and_getActiveRequests()
a public API that much. The only thing that will be documented and supported isObject.keys(getActiveResources()).length
, the rest remains undocumented! Yes, we also expose the resources increateHook({init})
, I don't like that either and I would really like to find a better solution. -
This gives the illusion that
getActiveResources
directly corresponds theresources
fromasync_hooks
which is not always the case. I do for example not believe Promise resources will be included and for sure user-land resources will not appear ingetActiveResources()
. That is directly misleading the user!
I likely missed some comments, but I feel there is some secrecy about what this is really for. For example, if it is for inspecting active timers, could we then not just add an API for that under require('timers')
? Similarly for any other resource type.
That way we can fully document the content and we don't mislead the user about how these resources correspond to those in createHook({init})
.
I definitely share the same concerns around the undocumented resource objects. We should take a step back and look at the use cases in detail. I'd rather not expose undocumented objects so if we do need this API, we should likely wrap the resource objects in something we can document. |
The solution for |
This concession was already made for async_hooks callbacks, this doesn't seem any different. Also, the same things are also exposed to any code that has access to the objects already (i.e. the code the made a
That is a bit of a problem, maybe documentation notes would solve it enough? I'm not really sure.
I put this in the OP after my last comment; It's nothing more special than what people have been using "The root why of this is that some tools (such as N|Solid) like to have access to this kind of thing so we can inspect what kind of resources are active in a live application at any arbitrary point in time."
The rest of the async_hooks api should then also be subject to that. I'm not sure that would really suit all use-cases though. Certainly some API stability would be nice. Regarding exposing handle owners: What do we do about requests ( |
I agree, let's fix it all. I don't buy the argument, that just because a mistake was made once we might as well repeat it. That is not how progress is made. And for
Yeah, I was hoping for some more details than that. I don't really know what "people" use
I'm sure we can come up with a reasonable solution for those cases. Maybe we can just cleanup the API for those objects and document them. |
I'm not sure how much time I can dedicate to that though, it's a pretty big issue. 😉 Just like async_hooks as it stands is necessary to some people, so is this.
One example could be: "find what ports are open on network sockets, if any". I haven't poked around on npm what all uses |
Also, the original original (x2) PR for this from @cjihrig read:
And seemed to garner a generally positive response. |
would it be semver major to change an internal system such that the "expected" output of this api changes? (e.g. i expect a bunch of timers but there's only one) if yes, i feel like this is exposing too much. otherwise it is fine. |
@devsnek It is one thing for us to say it's not semver-major, another for users to start depending on it permanently so that it's effectively so. @AndreasMadsen Would it be acceptable for this to land in its current shape, behind a runtime flag? This way embedders with resources to maintain possible breakages due to internals change can still have such a functionality, while we won't have to worry about backward compatibility. |
@TimothyGu i bring that up so that we can document if it should/shouldn't be dependable behavior. the difference between "use this api to see handles" and "use this api to see all X because each X has its own handle" are two different usages that could arise but we might not want people to think that the second will always be a thing. |
@devsnek That is a big part of the problem. With this, we are moving one step further on making users depend on all internal Wrap resources. That is not something we want. Experience also tells us that documentation isn't really a solution. Users will still depend on behavior that the documentation tells them not to and we will therefore still break modules in the future.
Sure. I think it should be put on the |
Since it maps by the handle's async_id's, I'd say it is more related to async_hooks than it is to anything else. Putting it on |
Not if we put it behind a flag 😄 |
We can't put every new thing behind a flag, just as we can't put every new thing on process. The uses of this are most closely aligned with async_hooks, even if there are differences in approach. Otherwise, it is at best a utility function that can go into util. |
I'd love to see some progress on this. Our (NodeSource's) downstream users keep on giving us the signal that the "what is Node doing right now?" question that we help answer via use of I share concern expressed in this thread about the kinds of objects being exposed here and I don't like that we have all of these different shapes of internal objects being exposed in a seemingly ad-hoc manner and it's something we need to figure out. But I can see that discussion extending for a significant period of time unless someone has a fully baked proposal they want to make right now. Aside from that, I quite like this proposal as it is now but would just like to see docs. So, here's a proposal, let me know if there are objections to this or suggested amendments:
|
Ping... where are we at on this? Would love to see progress. |
@Fishrock123 Any updates on this? |
Hey if anyone wants to pick this back up go ahead. I'm probably not going to, although I believe this is the correct approach. (I am no longer at an employer who needs such a thing and have real no need of it myself.) |
Is this somehow related to #21313? Even that one is closed it's still somehow on agenda to be done at some time. |
@Flarna Yes, you can effectively do the same thing with this. This is more flexible. |
I think the two are unrelated besides being both about the async hooks API. |
I believe the following would be roughly equivalent to that PR: async_hooks.getActiveResources()[async_hooks.executionAsyncId()] |
@nodejs/async_hooks Any chance someone wants to pick this up? |
My fly-by 2 cents describing a use-case for this: I want to start a long-running child process, then track every asynchronous thing that is started/stopped after the child process. Once every asynchronous thing is done, kill the child process: https://stackoverflow.com/questions/58515254/how-do-i-make-nodejs-terminate-even-if-i-have-non-essential-things-in-the-even |
8ae28ff
to
2935f72
Compare
This has been stalled for a while and has seen no further activity. Closing |
This change picks up the changes from the referenced PR and moves the implementation of `getActiveResources` to `util` to return a summary of the resources. Refs: nodejs#21453
Prototype of a new
getActiveResources()
API forasync_hooks
.Returns an object map of
{ <id>: <resource> }
, and differs slightly fromgetActiveHandles()
. (The old API used to return the handle owner property for some reason.)Currently, it works for all async_hooks resources except nextTick-s, which are probably not useful to expose in this way.
Reason being that nextTick-s almost always have no interesting information attached, and exist in async_hooks almost exclusively for continuation purposes. The same thing can pretty much be said for Immediate-s too, and I wouldn't be opposed to removing them from this.
As an alternative to not producing nextTicks, I think something along the lines of
getActiveResources(async_type_mask)
could be acceptable.There are two primary reasons for why this might be useful compared to
async_hooks
, and why_getActiveHandles()
is still useful today.destroy()
but also not prevent GC.The root why of this is that some tools (such as N|Solid) like to have access to this kind of thing so we can inspect what kind of resources are active in a live application at any arbitrary point in time.
@nodejs/diagnostics @mike-kaufman @gpotter2
Supersedes #21102 & probably also #21313
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes