-
-
Notifications
You must be signed in to change notification settings - Fork 0
docs: async-hooks documentation #2
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
docs: async-hooks documentation #2
Conversation
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.
Docs will need to be word wrapped before going into core. I'll let you decide when to take care of that.
doc/api/async_hooks.md
Outdated
all optional. Returns an `AsyncHook` | ||
|
||
|
||
* `init` {function} |
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.
nit: the value inside of the {}
is usually capitalized in core docs at least.
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.
cool will fix
doc/api/async_hooks.md
Outdated
|
||
|
||
function init(uid, type, triggerId, handle) { | ||
const activity = { uid, type, parentUid } |
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.
parentUid -> triggerId
doc/api/async_hooks.md
Outdated
process.on('exit', onexit) | ||
function onexit() { | ||
// Stop listening on the above hooks | ||
asyncHook.disable() |
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.
thought: should we automatically stop listening in the 'exit'
event?
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'd opt for not doing any magic here. It doesn't matter much anyways since the process is exiting ...
doc/api/async_hooks.md
Outdated
* `uid` {number} a unique id for the async operation | ||
|
||
|
||
### AsyncHook.enable |
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.
This should either be asyncHook.enable()
or AsyncHook#enable()
. Like this it looks like a static member (i.e. not one on the prototype).
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.
which one of these two is more common given this is a module method? cc @Fishrock123
doc/api/async_hooks.md
Outdated
### async_hooks.currentId() | ||
|
||
|
||
Returns the uid of the current context. |
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.
nit: "current execution context". remove a hair more ambiguity.
doc/api/async_hooks.md
Outdated
embedder API. | ||
|
||
|
||
## Embedder API |
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.
The preferred embedder API is to use AsyncEvent
. The async_hooks.emitInit()
, etc., were made for internals, but I could find reasonable need for them in user code. But want to make clear they should attempt to use AsyncEvent
first, if possible.
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.
OK will dig into that a bit more AsyncEvent
and update the docs as far as I'll understand things at that point ...
cb4c5f2
to
8745613
Compare
f068849
to
620fb61
Compare
doc/api/async_hooks.md
Outdated
|
||
|
||
The `async-hooks` module provides an API to register callbacks tracking the lifetime of asynchronous handles created | ||
inside a Node.js application. |
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.
Needs a terminology section: https://github.com/nodejs/node-eps/blob/e35d4813fdbbd99a751296e24361dba0d0dd9e10/XXX-asyncwrap-api.md#terminology
The top-level description should probably not include the word "handle".
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.
So, al the Node.js docs follow some order:
All sections and content within them must be alphabetical, the exception being if you have API and subheadings in the same spot, then the API references must be alphabetical but the sub-heading should usually go last.
Also, we tend to put examples after API references, except in the case of a top-level example.
8745613
to
13c8190
Compare
@Fishrock123 @trevnorris, ready for another review. Fixed a bunch of nits and integrated big parts from the EPS Most now comes from this EPS, except I reordered things a bit to clearly separate the different parts of the API. I also removed the original example I had in there, as now lots of examples are already included in numerous places. LMK what you think at this point. |
97194bd
to
7dae377
Compare
175108c
to
df8e8e5
Compare
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 think it would also be good to have a section explaining that you must sue process._rawDebug()
to log within a look so as to prevent an infinite loop.
doc/api/async_hooks.md
Outdated
|
||
|
||
> Stability: 2 - Stable | ||
|
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.
extra spaces?
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 you clarify? Missing spaces, need to add them and where?
doc/api/async_hooks.md
Outdated
Requests are short lived data structures created to accomplish one task. The | ||
callback for a request should always and only ever fire one time. Which is when | ||
the assigned task has either completed or encountered an error. Requests are | ||
used by handles to perform these tasks. Such as accepting a new connection or |
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.
tasks, such as
-- the last sentence probably shouldn't be it's own.
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.
OK will fix.
doc/api/async_hooks.md
Outdated
const async_hooks = require('async_hooks'); | ||
|
||
// Return the id of the current execution context. Useful for tracking state | ||
// and retrieving the handle of the current trigger without needing to use an |
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.
You mean retrieving the handle if the user has stored it?
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 probably be id
instead of handle .. I agree it's confusing.
This came from the EP (slightly adapted) so @trevnorris should know.
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.
... retrieving the handle of the current trigger
That comment dates back to when I had implemented a map to keep track of all resources, and there was async_hooks.getResourceById()
. Which would return the resource from the map, but it ended up being too costly. So it was removed.
doc/api/async_hooks.md
Outdated
// current execution scope to fire. | ||
const tid = aysnc_hooks.triggerId(); | ||
|
||
// Create a new instance of AsyncHook. All of these callbacks are optional. |
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.
a new AsyncHook instance.
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.
Hairsplitting, but I've got no strong opinion, so will fix.
doc/api/async_hooks.md
Outdated
|
||
// Disable listening for new asynchronous events. Though this will not prevent | ||
// callbacks from firing on asynchronous chains that have already run within | ||
// the scope of an enabled AsyncHook instance. |
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.
It will actually prevent those
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.
Need clarification from @trevnorris here.
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 updated the EP to simply say:
// Disable listening for all new asynchronous events.
doc/api/async_hooks.md
Outdated
}): | ||
``` | ||
|
||
It is important to note that the id returned has to do with execution timing. |
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.
returned from `currentId()`
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.
Will fix.
|
||
The class `AsyncEvent` was designed to be extended from for embedder's async | ||
resources. Using this users can easily trigger the lifetime events of their | ||
own resources. |
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.
Perhaps we want to put in a thing about that I/O pools need to use this?
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.
Need more details on that or maybe you or @trevnorris can suggest the addition here?
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.
@Fishrock123 can you clarify what you mean?
doc/api/async_hooks.md
Outdated
|
||
// Call after() hooks. It is important that before/after calls are unwound | ||
// in the same order they are called. Otherwise an unrecoverable exception | ||
// will be made. |
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.
Perhaps this comment should go under the actual api header with an example?
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.
Yeah, makes sense. Will fix.
doc/api/async_hooks.md
Outdated
#### `AsyncEvent(type[, triggerId])` | ||
|
||
* arguments | ||
* type {String} the type of ascync event |
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.
async
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.
Will fix.
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.
The argument names are supposed to be surrounded in backticks. e.g. `type`
. Please change throughout the document.
If the user's callback throws an exception then `emitAfter()` will | ||
automatically be called for all `id`'s on the stack if the error is handled by | ||
a domain or `'uncaughtException'` handler. So there is no need to guard against | ||
this. |
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.
Perhaps we should say it should not be called or an example given?
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.
Not fully sure what you mean. What should not be called?
df8e8e5
to
b3aed32
Compare
33c2eb5
to
97a27f1
Compare
b3aed32
to
dc4833d
Compare
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.
Thanks for the work. I like the added example of using the AsyncEvent
API.
doc/api/async_hooks.md
Outdated
# Async Hooks | ||
|
||
|
||
> Stability: 2 - Stable |
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 believe the initial release will be labeled 1 - Experimental
so that we have a major version to make any necessary tweaks.
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.
Fixed
doc/api/async_hooks.md
Outdated
lifetime of asynchronous resources created inside a Node.js application. | ||
|
||
At its simplest form it can track metadata about each resource and log it when | ||
the program exits. |
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.
This doesn't make much sense to me. The absolute simplest would be to log metadata about asynchronous resources when they occur.
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.
Removed the paragraph
doc/api/async_hooks.md
Outdated
const async_hooks = require('async_hooks'); | ||
|
||
// Return the id of the current execution context. Useful for tracking state | ||
// and retrieving the handle of the current trigger without needing to use an |
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.
... retrieving the handle of the current trigger
That comment dates back to when I had implemented a map to keep track of all resources, and there was async_hooks.getResourceById()
. Which would return the resource from the map, but it ended up being too costly. So it was removed.
doc/api/async_hooks.md
Outdated
|
||
// Disable listening for new asynchronous events. Though this will not prevent | ||
// callbacks from firing on asynchronous chains that have already run within | ||
// the scope of an enabled AsyncHook instance. |
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 updated the EP to simply say:
// Disable listening for all new asynchronous events.
doc/api/async_hooks.md
Outdated
|
||
Registers functions to be called for different lifetime events of each async | ||
operation. | ||
The above callbacks registered via an `AsyncHooks` instance fire during specific |
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.
If that is removed I'd suggest explicitly mentioning all four callbacks. e.g.
The callbacks
init()
/before()
/after()
/destroy()
are registered via...
doc/api/async_hooks.md
Outdated
async_hooks.createHook({ | ||
init: (id, type, triggerId) => { | ||
const cId = async_hooks.currentId(); | ||
process._rawDebug(' '.repeat(ws) + |
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.
Did you add that console.*()
should never be used from hook callbacks? May need to mention this.
doc/api/async_hooks.md
Outdated
SIGNALWRAP(7): trigger: 4 scope: 4 | ||
>>> 4 | ||
after: 4 | ||
after: 5 |
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.
The script above, and this output, were both updated in the EP. Please reference.
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.
Updated the output .. didn't see any changes to the script.
Note that we're using class like function declarations (instead of arrow functions) as per request by @Fishrock123
**Note:** Some resources depend on GC for cleanup. So if a reference is made to | ||
the `resource` object passed to `init()` it's possible that `destroy()` is | ||
never called. Causing a memory leak in the application. Of course if you know | ||
the resource doesn't depend on GC then this isn't an issue. |
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.
It's anything that uses MakeWeak()
in C++. Can throw that list together if needed.
|
||
The class `AsyncEvent` was designed to be extended from for embedder's async | ||
resources. Using this users can easily trigger the lifetime events of their | ||
own resources. |
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.
@Fishrock123 can you clarify what you mean?
doc/api/async_hooks.md
Outdated
#### `AsyncEvent(type[, triggerId])` | ||
|
||
* arguments | ||
* type {String} the type of ascync event |
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.
The argument names are supposed to be surrounded in backticks. e.g. `type`
. Please change throughout the document.
@Fishrock123 @trevnorris addressed the nits. Still need input/clarification on the below |
97a27f1
to
79b11ce
Compare
17edc94
to
e5193f7
Compare
79b11ce
to
1ff2dfb
Compare
e5193f7
to
4dac48a
Compare
So I fixed the nits pointed out by Trevor, but still need some clarification from @Fishrock123 for some of the above. |
TTYWRAP(6) -> Timeout(4) -> TIMERWRAP(5) -> TickObject(3) -> root(1) | ||
``` | ||
|
||
The `TCPWRAP` isn't part of this graph; evne though it was the reason for |
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.
s/evne/even/
```js | ||
const async_hooks = require('async_hooks'); | ||
|
||
// Return the id of the current execution context. |
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.
Probably worth defining 'execution context' somewhere.
hostname is actually synchronous, but to maintain a completely asynchronous API | ||
the user's callback is placed in a `process.nextTick()`. | ||
|
||
The graph only shows **when** a resource was created. Not **why**. So to track |
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.
Not why. So to track the why use
triggerId
.
This is a bit awkward
event | ||
* Returns {AsyncEvent} A reference to `asyncHook`. | ||
|
||
Example usage: |
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.
This seems less like an embedder's use but an APM/wrapper's use. I'd think that the embedder would put the emitBefore and
emitAfterinside
function this.db.getnot the
getInfo` wrapper?
@brycebaril let's continue discussion here: nodejs#12953 |
const async_hooks = require('async_hooks'); | ||
|
||
// Return new unique id for a constructing handle. | ||
const id = async_hooks.newUid(); |
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 this be newId()
?
WIP PR to get Feedback.
@rvagg @Fishrock123 @trevnorris