-
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: run destroy callbacks before normal exit #13286
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4531,6 +4531,8 @@ inline int Start(Isolate* isolate, IsolateData* isolate_data, | |
} while (more == true); | ||
} | ||
|
||
AsyncWrap::RunDestroyCbs(&env); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I also don't like to pollute the event loop code if it can be handled by libuv. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately that seems to change the timing of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You mean you'd prefer we use Honestly if you want the callbacks to run before the poll phase then it might be worth it to run it as a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @addaleax ah. think I see what's going on. will get another fix for this in a moment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @trevnorris Thanks – I’ll pick the |
||
|
||
env.set_trace_sync_io(false); | ||
|
||
const int exit_code = EmitExit(&env); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
'use strict'; | ||
// Test that async ids that are added to the destroy queue while running a | ||
// `destroy` callback are handled correctly. | ||
|
||
const common = require('../common'); | ||
const assert = require('assert'); | ||
const net = require('net'); | ||
const async_hooks = require('async_hooks'); | ||
|
||
const initCalls = new Set(); | ||
let destroyTcpWrapCallCount = 0; | ||
let srv2; | ||
|
||
async_hooks.createHook({ | ||
init: common.mustCallAtLeast((id, provider, triggerId) => { | ||
if (provider === 'TCPWRAP') | ||
initCalls.add(id); | ||
}, 2), | ||
destroy: common.mustCallAtLeast((id) => { | ||
if (!initCalls.has(id)) return; | ||
|
||
switch (destroyTcpWrapCallCount++) { | ||
case 0: | ||
// Trigger the second `destroy` call. | ||
srv2.close(); | ||
break; | ||
case 2: | ||
assert.fail('More than 2 destroy() invocations'); | ||
break; | ||
} | ||
}, 2) | ||
}).enable(); | ||
|
||
// Create a server to trigger the first `destroy` callback. | ||
net.createServer().listen(0).close(); | ||
srv2 = net.createServer().listen(0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This abuses node internals. We should assume that net.createServer().listen({port: 0, host: 'localhost'}).close(); Instead it needs to be written as such:
This means you can't reliably call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IOW, the those two lines should instead be written as such: srv2 = net.createServer().listen(0, () => {
net.createServer().listen(0, function() { this.close() });
}); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @trevnorris Is there anything in Node that always closes synchronously? Anyway, I’ve updated #13353 to just use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @addaleax everything libuv that "closes" always goes through |
||
|
||
process.on('exit', () => assert.strictEqual(destroyTcpWrapCallCount, 2)); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
'use strict'; | ||
|
||
// Regression test for https://github.com/nodejs/node/issues/13262 | ||
|
||
const common = require('../common'); | ||
const assert = require('assert'); | ||
const async_hooks = require('async_hooks'); | ||
|
||
let seenId, seenResource; | ||
|
||
async_hooks.createHook({ | ||
init: common.mustCall((id, provider, triggerId, resource) => { | ||
seenId = id; | ||
seenResource = resource; | ||
assert.strictEqual(provider, 'Immediate'); | ||
assert.strictEqual(triggerId, 1); | ||
}), | ||
before: common.mustNotCall(), | ||
after: common.mustNotCall(), | ||
destroy: common.mustCall((id) => { | ||
assert.strictEqual(seenId, id); | ||
}) | ||
}).enable(); | ||
|
||
const immediate = setImmediate(common.mustNotCall()); | ||
assert.strictEqual(immediate, seenResource); | ||
clearImmediate(immediate); |
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.
Removing this fixes the issue tested by
parallel/test-async-hooks-close-during-destroy
. If somebody feels like I should, I can split it into a second commit.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 would be nice for the purpose of adding a good commit message descibing the 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.
@addaleax If you don't clear the
std::vector<double>
then destroy ids list will continue to call the destroy hooks for all the previously entered asyncIds.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.
@trevnorris Just before the loop above, you already swapped the list with an empty vector, which is the right way to solve that. Re-clearing the list may actually clear too much (you can try out the test file here yourself, if you like).
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.
ah yup. you're right.