-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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 destroy event for gced AsyncResources #16998
async_hooks: Add destroy event for gced AsyncResources #16998
Conversation
lib/async_hooks.js
Outdated
@@ -259,8 +262,15 @@ function validateAsyncId(asyncId, type) { | |||
|
|||
// Embedder API // | |||
|
|||
const undestroyedAsyncIds = new Set(); |
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.
Are Set
s a thing in lib/
, or is that too much of a problem for perf?
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 perfectly fine.
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.
What’s the reason for this, though? Avoiding double cleanup when the implementor emits destroy
manually? Can you add a comment?
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.
Exactly. Will do.
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 possible, I would like to avoid yet another global state and yet another special emit function :)
Is it not possible to read a property from the handle
object in MakeCallback
? Then we could just have another symbol property on in the handle
object that indicates if emitDestroy
was called manually.
Another option is forcing the user to either always call emitDestroy()
or otherwise never call emitDestroy()
, depending on the optional flag is also an option.
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.
Ahh I see what you mean. That should be possible; I think v8 doesn't clear up the object before the weak callback gets invoked. I'll implement that.
What are the other use-cases?
I was thinking about resources which allow explicit disposal, like imagine a connection where you could call conn.close()
or just let it fall out of scope. I think the expectation there would be for the destroy event to emitted at the time of the close call rather than at GC time (necessitating a way to prevent a double call).
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.
After thinking about it some, that would not allow us to set the symbol on AsyncResource if the asyncId is destroyed by the sensitive API (since we don't have an AsyncResource reference available there).
Does there currently not exist a map with all async ids where we could store state in at all? I thought until now that async_id_fields
did so we could shove an additional field in there, but just realized that that's just global state management after looking at 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.
Don't worry about the sensitive API. We will be deprecating that anyway and I think it is perfectly fine to require the user call emitDestroy
manually if they insist on using a low-level API.
Does there currently not exist a map with all async ids where we could store state in at all?
No such map exists.
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.
Unfortunately, after testing it, it seems like v8 frees the object before the weakcallback is called, so we can't attach props there either 😞
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.
Here we go, found a solution by introducing another object into it for a level of indirection. 🎉
That good with you?
src/async-wrap.h
Outdated
@@ -157,6 +157,9 @@ class AsyncWrap : public BaseObject { | |||
|
|||
virtual size_t self_size() const = 0; | |||
|
|||
class DestroyParam; |
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 we either have to leave this public, or move RegisterDestroyHook into AsyncWrap
. Since the other registered methods don't do that, I wasn't sure if that'd work?
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.
Without having looked too much, you can assume that any code behind NODE_WANT_INTERNALS
(including this header file) is not considered public
src/async-wrap.cc
Outdated
v8::Persistent<Function> callback; | ||
}; | ||
void AsyncWrap::WeakCallback( | ||
const v8::WeakCallbackInfo<AsyncWrap::DestroyParam> &info |
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.
We generally use left-leaning pointers and references, i.e. … DestroyParam>& info
.
src/async-wrap.cc
Outdated
double asyncId; | ||
v8::Persistent<Function> callback; | ||
}; | ||
void AsyncWrap::WeakCallback( |
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.
Can you leave two lines of space between definitions? Otherwise this is very dense code :)
src/async-wrap.cc
Outdated
@@ -407,6 +407,40 @@ static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) { | |||
} | |||
|
|||
|
|||
class AsyncWrap::DestroyParam { |
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 don’t think this needs to be on AsyncWrap
, it’s kind of it’s own different thing (it can stay in this class though)
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 just dropping up(/down?) into the node
namespace, but keep it in the same file?
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, exactly :)
src/async-wrap.cc
Outdated
|
||
Environment* env = Environment::GetCurrent(args); | ||
|
||
v8::Persistent<Object> target(env->isolate(), args[0].As<Object>()); |
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 this might be causing trouble because there’s no way to reset the persistent if it’s stack-allocated? Maybe that’s not an issue, but I’d prefer it if this was a property on DestroyParam
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.
We're only using this to register the weak callback and let it get cleaned up afterwards. Do we need to keep it alive for v8?
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 making me a bit uneasy at least in the sense that there are comments in v8.h that hint at a future change towards v8::Persistent
resetting itself when the destructor is called (which I would welcome, I think):
Lines 633 to 634 in b204b09
* At present kResetInDestructor is not set, but that will change in a future | |
* version. |
lib/async_hooks.js
Outdated
class AsyncResource { | ||
constructor(type, triggerAsyncId = initTriggerId()) { | ||
constructor(type, triggerAsyncId = initTriggerId(), opts = {}) { |
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.
Given that that triggerAsyncId
is also optional. I think the signature should be:
// won't actually work
constructor(type, options = {
triggerAsyncId = initTriggerId(),
disableTracking: true
})
For backward compatibility, we can check with typeof options === 'number'
and also deprecate that usage.
lib/async_hooks.js
Outdated
@@ -278,6 +288,11 @@ class AsyncResource { | |||
emitInitScript( | |||
this[async_id_symbol], type, this[trigger_async_id_symbol], this | |||
); | |||
|
|||
if (!opts.disableTracking) { |
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.
Tracking/trace can mean so many things. Maybe call it if (options.manualDestroy)
?
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.
Hmm, we don't actually mind manualDestroy since we prevent double destroys. What we actually dislike is a delayed (after GC) sensitive emitDestroy. Soo delayedSensitiveDestroy
? May be too long...
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 don’t mind long names (I actually think they are a great idea and we need more of them), but delayedSensitiveDestroy
doesn’t seem to say much imo … how about requireManualDestroy
if you want to be explicit about what is optional/required?
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.
Sounds good to me.
src/async-wrap.cc
Outdated
delete p; | ||
|
||
Local<v8::Primitive> undef = Undefined(info.GetIsolate()); | ||
fn->Call( |
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 entirely sure how this SetWeek
works but we have had issues before, where calling into JavaScript when the GC is running caused a process crash. This is why we have PushBackDestroyAsyncId
.
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 delete your other comment? I think it'd be possible to do this rather easily, if we save a Map<AsyncId, destroyManual> in JS, but I can't quite figure out how MakeCallback
works for the other thing you mentioned.
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 got collapsed #16998 (comment)
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 make it such that it calls emitNativeDestroy
directly (some suggestions in #16998 (comment)) then it should be straightforward to use PushBackDestroyAsyncId
.
PushBackDestroyAsyncId
basically just calls emitNativeDestroy
when it is safe.
doc/api/async_hooks.md
Outdated
@@ -566,11 +568,14 @@ asyncResource.asyncId(); | |||
asyncResource.triggerAsyncId(); | |||
``` | |||
|
|||
#### `AsyncResource(type[, triggerAsyncId])` | |||
#### `AsyncResource(type[, triggerAsyncId [, options]])` |
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.
remember to update documentation
doc/api/async_hooks.md
Outdated
* `disableTracking` {boolean} Disables automatic `emitDestroy` when the | ||
object is garbage collected. **Default:** `false` | ||
* `requireManualDestroy` {boolean} Disables automatic `emitDestroy` when the | ||
object is garbage collected. You usually do not need to set this option (even |
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.
Please avoid using informal pronouns like you
in the docs.
src/async-wrap.cc
Outdated
p->propBag.Reset(env->isolate(), args[2].As<Object>()); | ||
|
||
p->target.SetWeak( | ||
p, AsyncWrap::WeakCallback, v8::WeakCallbackType::kParameter); |
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.
Isn't this stuff rather perf-costly?
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.
Just checked this with hrtime
a bit:
It appears that while not fast there's a bigger problem:
The .As<Object>()
are very slow during instantiation of AsyncResource
. Just leaving p->target.Reset(isolate, args[0].As<Object>());
in the Register, moves us from 0.2s for 5MM instantions to 2.4s. Is there any way to avoid the v8 ::Cast for that?
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.
.As<T>
is just an unchecked cast; it essentially compiles down to zero instructions at run-time. It's the new
and .Reset()
calls that are slow.
The .SetWeak()
call itself isn't very slow but it creates more work for the garbage collector.
lib/async_hooks.js
Outdated
this[destroyedSymbol] = { destroyed: false }; | ||
|
||
emitInitScript( | ||
this[async_id_symbol], type, this[trigger_async_id_symbol], this | ||
); | ||
|
||
if (!opts.requireManualDestroy) { | ||
registerDestroyHook(this, this[async_id_symbol], this[destroyedSymbol]); | ||
registerDestroyHook(this, this[async_id_symbol], this[destroyedSymbol], "destroyed"); |
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.
Typically we solve the performance penalty of creating a string in C++ by having it as a global. We have a lot of those so don't feel bad about adding another one: https://github.com/nodejs/node/blob/master/src/env.h#L100
doc/api/async_hooks.md
Outdated
@@ -543,12 +543,14 @@ will occur and the process will abort. | |||
The following is an overview of the `AsyncResource` API. | |||
|
|||
```js | |||
const { AsyncResource } = require('async_hooks'); | |||
const { AsyncResource, triggerAsyncId } = require('async_hooks'); |
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.
Maybe this should be executionAsyncId
, to match the code below?
@Sebmaster it sounds like you did a benchmark of Even if there is a performance penalty it might still be fine. edit: documentation for our benchmark suite can be found here: https://github.com/nodejs/node/blob/master/doc/guides/writing-and-running-benchmarks.md |
@AndreasMadsen Is there a way to specify expose-gc in the benchmark? If not I'm probably just gonna compare instantiation rather than also including gc runtime. |
@Sebmaster yes, you can actually do it with the |
Sweet. Added. Results for me:
|
I wish I could remember how to read that 😂 . I think you can run:
Unfortunately, we don't have a CI job for parameter comparing :/ |
Here you go:
|
@Sebmaster Thanks . That is definetly a big difference (15x). If we can't do anything to improve this then we should consider documenting that |
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.
LGTM.
@Sebmaster I'm very impressed by your work, it is quite a complex change for a first-time contribution. You have been extremely responsive and understood all of our feedback, which often is a big challenge.
Be proud :)
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.
LGTM, with a few comments
nice work!
src/async-wrap.cc
Outdated
|
||
Environment* env = Environment::GetCurrent(info.GetIsolate()); | ||
DestroyParam* p = info.GetParameter(); | ||
Local<Object> propBag = PersistentToLocal(info.GetIsolate(), p->propBag); |
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.
Tiny nit: prop_bag
for local variables (See https://github.com/nodejs/node/blob/master/CPP_STYLE_GUIDE.md :) )
src/async-wrap.cc
Outdated
Local<Object> propBag = PersistentToLocal(info.GetIsolate(), p->propBag); | ||
|
||
Local<Value> val = propBag->Get(env->destroyed_string()); | ||
if (!val->BooleanValue()) { |
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 (val->IsFalse())
? Otherwise you’ll need to switch to the variant of BooleanValue()
that is not deprecated (i.e. the one that takes a Local<Context> context
argument)
src/async-wrap.cc
Outdated
|
||
Isolate* isolate = args.GetIsolate(); | ||
DestroyParam* p = new DestroyParam(); | ||
p->asyncId = args[1]->NumberValue(); |
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.
Can you use args[1].As<Number>()->Value()
? This is deprecated (and slower for when we don’t have val->IsNumber() == true
).
src/async-wrap.cc
Outdated
if (!val->BooleanValue()) { | ||
PushBackDestroyAsyncId(env, p->asyncId); | ||
} | ||
p->propBag.Reset(); |
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.
Can you maybe CHECK(p->target.IsEmpty());
too, just to be sure?
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.
That fails. I'm pretty sure the pointer just becomes invalid, but still points somewhere.
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.
Hm, in that case, I would assume the pointer is still valid – but either way, calling .Reset()
on it should be fine?
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.
Hm, in that case, I would assume the pointer is still valid – but either way, calling .Reset()
on it should be fine?
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.
Oh, that works. I was pretty sure that failed previously, but owell, apparently misremembering.
Okay, I think we’re all set here! 👍 |
I was almost getting ready to paste the linter failure here 😄 I don’t think we need to kick off another CI run for this. |
I need to feel safe: https://ci.nodejs.org/job/node-test-pull-request/11471/ |
@Sebmaster Sorry, it looks you might have to rebase this now that #15538 has landed … :( |
In cases where libraries create AsyncResources which may be emitting more events depending on usage, the only way to ensure that destroy is called properly is by calling it when the resource gets garbage collected. Fixes: #16153
Done. Building took its sweet time 😁 |
One issue, but it is just a flaky test: #14568 |
Landed in 22901d8, thanks for the PR! 🎉 |
In cases where libraries create AsyncResources which may be emitting more events depending on usage, the only way to ensure that destroy is called properly is by calling it when the resource gets garbage collected. Fixes: #16153 PR-URL: #16998 Fixes: #16153 Reviewed-By: Andreas Madsen <amwebdk@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
@addaleax Is there a process for getting this into the current release branches, or is this a v10-only thing? |
@Sebmaster This should be picked up automatically, I think the only issue is that nobody in @nodejs/release has done a 9.x release in a while? I don’t currently have the bandwidth to prepare one myself, sorry |
Ah, that's fine, just saw that 9.2.0 came out after the merge and wasn't sure if it just didn't make the cut. |
Hm it may have had conflicts when I cut v9.2.0. I'll dig into it after v9.2.1 and try to get it in a release next Tuesday-ish |
In cases where libraries create AsyncResources which may be emitting more events depending on usage, the only way to ensure that destroy is called properly is by calling it when the resource gets garbage collected. Fixes: #16153 PR-URL: #16998 Fixes: #16153 Reviewed-By: Andreas Madsen <amwebdk@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
In cases where libraries create AsyncResources which may be emitting more events depending on usage, the only way to ensure that destroy is called properly is by calling it when the resource gets garbage collected. Fixes: nodejs#16153 PR-URL: nodejs#16998 Backport-PR-URL: nodejs#18179 Fixes: nodejs#16153 Reviewed-By: Andreas Madsen <amwebdk@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
In cases where libraries create AsyncResources which may be emitting more events depending on usage, the only way to ensure that destroy is called properly is by calling it when the resource gets garbage collected. Backport-PR-URL: #18179 Fixes: #16153 PR-URL: #16998 Fixes: #16153 Reviewed-By: Andreas Madsen <amwebdk@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
Notable changes: * deps: * update V8 to 6.2.414.46 (Michaël Zasso) [#16413](#16413) * revert ABI breaking changes in V8 6.2 (Anna Henningsen) [#16413](#16413) * upgrade libuv to 1.19.1 (cjihrig) [#18260](#18260) * re land npm 5.6.0 (Myles Borins) [#18625](#18625) * ICU 60 bump (Steven R. Loomis) [#16876](#16876) * crypto: * Support both OpenSSL 1.1.0 and 1.0.2 (David Benjamin) [#16130](#16130) * warn on invalid authentication tag length (Tobias Nießen) [#17566](#17566) * async_hooks: * update defaultTriggerAsyncIdScope for perf (Anatoli Papirovski) [#18004](#18004) * use typed array stack as fast path (Anna Henningsen) [#17780](#17780) * use scope for defaultTriggerAsyncId (Andreas Madsen) [#17273](#17273) * separate missing from default context (Andreas Madsen) [#17273](#17273) * rename initTriggerId (Andreas Madsen) [#17273](#17273) * deprecate undocumented API (Andreas Madsen) [#16972](#16972) * add destroy event for gced AsyncResources (Sebastian Mayr) [#16998](#16998) * add trace events to async_hooks (Andreas Madsen) [#15538](#15538) * set HTTPParser trigger to socket (Andreas Madsen) [#18003](#18003) * add provider types for net server (Andreas Madsen) [#17157](#17157) * n-api: * add helper for addons to get the event loop (Anna Henningsen) [#17109](#17109) * cli: * add --stack-trace-limit to NODE_OPTIONS (Anna Henningsen) [#16495](#16495) * console: * add support for console.debug (Benjamin Zaslavsky) [#17033](#17033) * module: * add builtinModules (Jon Moss) [#16386](#16386) * replace default paths in require.resolve() (cjihrig) [#17113](#17113) * src: * add helper for addons to get the event loop (Anna Henningsen) [#17109](#17109) * add process.ppid (cjihrig) [#16839](#16839) * http: * support generic `Duplex` streams (Anna Henningsen) [#16267](#16267) * add rawPacket in err of `clientError` event (XadillaX) [#17672](#17672) * better support for IPv6 addresses (Mattias Holmlund) [#14772](#14772) * net: * remove ADDRCONFIG DNS hint on Windows (Bartosz Sosnowski) [#17662](#17662) * process: * fix reading zero-length env vars on win32 (Anna Henningsen) [#18463](#18463) * tls: * unconsume stream on destroy (Anna Henningsen) [#17478](#17478) * process: * improve unhandled rejection message (Madara Uchiha) [#17158](#17158) * stream: * remove usage of *State.highWaterMark (Calvin Metcalf) [#12860](#12860) * trace_events: * add executionAsyncId to init events (Andreas Madsen) [#17196](#17196) PR-URL: #18336
Notable changes: * deps: * update V8 to 6.2.414.46 (Michaël Zasso) [#16413](#16413) * revert ABI breaking changes in V8 6.2 (Anna Henningsen) [#16413](#16413) * upgrade libuv to 1.19.1 (cjihrig) [#18260](#18260) * re land npm 5.6.0 (Myles Borins) [#18625](#18625) * ICU 60 bump (Steven R. Loomis) [#16876](#16876) * crypto: * Support both OpenSSL 1.1.0 and 1.0.2 (David Benjamin) [#16130](#16130) * warn on invalid authentication tag length (Tobias Nießen) [#17566](#17566) * async_hooks: * update defaultTriggerAsyncIdScope for perf (Anatoli Papirovski) [#18004](#18004) * use typed array stack as fast path (Anna Henningsen) [#17780](#17780) * use scope for defaultTriggerAsyncId (Andreas Madsen) [#17273](#17273) * separate missing from default context (Andreas Madsen) [#17273](#17273) * rename initTriggerId (Andreas Madsen) [#17273](#17273) * deprecate undocumented API (Andreas Madsen) [#16972](#16972) * add destroy event for gced AsyncResources (Sebastian Mayr) [#16998](#16998) * add trace events to async_hooks (Andreas Madsen) [#15538](#15538) * set HTTPParser trigger to socket (Andreas Madsen) [#18003](#18003) * add provider types for net server (Andreas Madsen) [#17157](#17157) * n-api: * add helper for addons to get the event loop (Anna Henningsen) [#17109](#17109) * cli: * add --stack-trace-limit to NODE_OPTIONS (Anna Henningsen) [#16495](#16495) * console: * add support for console.debug (Benjamin Zaslavsky) [#17033](#17033) * module: * add builtinModules (Jon Moss) [#16386](#16386) * replace default paths in require.resolve() (cjihrig) [#17113](#17113) * src: * add helper for addons to get the event loop (Anna Henningsen) [#17109](#17109) * add process.ppid (cjihrig) [#16839](#16839) * http: * support generic `Duplex` streams (Anna Henningsen) [#16267](#16267) * add rawPacket in err of `clientError` event (XadillaX) [#17672](#17672) * better support for IPv6 addresses (Mattias Holmlund) [#14772](#14772) * net: * remove ADDRCONFIG DNS hint on Windows (Bartosz Sosnowski) [#17662](#17662) * process: * fix reading zero-length env vars on win32 (Anna Henningsen) [#18463](#18463) * tls: * unconsume stream on destroy (Anna Henningsen) [#17478](#17478) * process: * improve unhandled rejection message (Madara Uchiha) [#17158](#17158) * stream: * remove usage of *State.highWaterMark (Calvin Metcalf) [#12860](#12860) * trace_events: * add executionAsyncId to init events (Andreas Madsen) [#17196](#17196) PR-URL: #18336
Notable changes: * deps: * update V8 to 6.2.414.46 (Michaël Zasso) [nodejs#16413](nodejs#16413) * revert ABI breaking changes in V8 6.2 (Anna Henningsen) [nodejs#16413](nodejs#16413) * upgrade libuv to 1.19.1 (cjihrig) [nodejs#18260](nodejs#18260) * re land npm 5.6.0 (Myles Borins) [nodejs#18625](nodejs#18625) * ICU 60 bump (Steven R. Loomis) [nodejs#16876](nodejs#16876) * crypto: * Support both OpenSSL 1.1.0 and 1.0.2 (David Benjamin) [nodejs#16130](nodejs#16130) * warn on invalid authentication tag length (Tobias Nießen) [nodejs#17566](nodejs#17566) * async_hooks: * update defaultTriggerAsyncIdScope for perf (Anatoli Papirovski) [nodejs#18004](nodejs#18004) * use typed array stack as fast path (Anna Henningsen) [nodejs#17780](nodejs#17780) * use scope for defaultTriggerAsyncId (Andreas Madsen) [nodejs#17273](nodejs#17273) * separate missing from default context (Andreas Madsen) [nodejs#17273](nodejs#17273) * rename initTriggerId (Andreas Madsen) [nodejs#17273](nodejs#17273) * deprecate undocumented API (Andreas Madsen) [nodejs#16972](nodejs#16972) * add destroy event for gced AsyncResources (Sebastian Mayr) [nodejs#16998](nodejs#16998) * add trace events to async_hooks (Andreas Madsen) [nodejs#15538](nodejs#15538) * set HTTPParser trigger to socket (Andreas Madsen) [nodejs#18003](nodejs#18003) * add provider types for net server (Andreas Madsen) [nodejs#17157](nodejs#17157) * n-api: * add helper for addons to get the event loop (Anna Henningsen) [nodejs#17109](nodejs#17109) * cli: * add --stack-trace-limit to NODE_OPTIONS (Anna Henningsen) [nodejs#16495](nodejs#16495) * console: * add support for console.debug (Benjamin Zaslavsky) [nodejs#17033](nodejs#17033) * module: * add builtinModules (Jon Moss) [nodejs#16386](nodejs#16386) * replace default paths in require.resolve() (cjihrig) [nodejs#17113](nodejs#17113) * src: * add helper for addons to get the event loop (Anna Henningsen) [nodejs#17109](nodejs#17109) * add process.ppid (cjihrig) [nodejs#16839](nodejs#16839) * http: * support generic `Duplex` streams (Anna Henningsen) [nodejs#16267](nodejs#16267) * add rawPacket in err of `clientError` event (XadillaX) [nodejs#17672](nodejs#17672) * better support for IPv6 addresses (Mattias Holmlund) [nodejs#14772](nodejs#14772) * net: * remove ADDRCONFIG DNS hint on Windows (Bartosz Sosnowski) [nodejs#17662](nodejs#17662) * process: * fix reading zero-length env vars on win32 (Anna Henningsen) [nodejs#18463](nodejs#18463) * tls: * unconsume stream on destroy (Anna Henningsen) [nodejs#17478](nodejs#17478) * process: * improve unhandled rejection message (Madara Uchiha) [nodejs#17158](nodejs#17158) * stream: * remove usage of *State.highWaterMark (Calvin Metcalf) [nodejs#12860](nodejs#12860) * trace_events: * add executionAsyncId to init events (Andreas Madsen) [nodejs#17196](nodejs#17196) PR-URL: nodejs#18336
In cases where libraries create AsyncResources which may be emitting
more events depending on usage, the only way to ensure that destroy is
called properly is by calling it when the resource gets garbage
collected.
Fixes: #16153
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passespython tools/test.py -J --mode=release async-hooks/test-callback-error
fails for me on master as well as this branch...Affected core subsystem(s)
doc, async_hooks
/cc @addaleax