-
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: move statement #14054
async_hooks: move statement #14054
Conversation
The simplification conflicts with #14051 If you think this simplification is better, could you split up the PR so we can review the commits seperately? |
@AndreasMadsen Oops. Hm, I don't have a strong opinion. As you've worked far more with async_hooks, I'd say it's your call. |
lib/async_hooks.js
Outdated
Error.captureStackTrace(o, fatalError); | ||
process._rawDebug(o.stack); | ||
} | ||
process._rawDebug(e.stack); |
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... We might want this exposed as the standard way to fail from a callback or Promise.catch
... so failing with just a message might be useful... Also we're trying to remove non NodeError
s from the code (even if they are just stack containers).
IMHO restore the weird captureStackTrace
case, and please add it to the module.exports = {
Ref: #13839 (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.
Nevermind re #14051 (comment), I'll move it to test/common
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.
IMHO restore the weird
captureStackTrace
case, and please add it to themodule.exports = {
I completely disagree, there is no good reason for stack trace to start in fatalError
, it should start where the error occurred. And async_hooks
should definitely not export fatalError
, as fatalError
has nothing to do with 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.
@AndreasMadsen just beat me by a minute 😄
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.
Only first commit
A bit off topic but your comment made me think we might at some point want to create long stacks for our exceptions, probably just for |
What are "long stacks"? |
I have now confirmed that the issue in #14051 has nothing to do with my changes. So I think I prefer my approach in #14051. This is how it is done in the async_hooks C++, I think it makes sense to use the same approach in async_hooks JS. |
async-context stacktraces. But that discussion should be in a separate thread. |
16f125d
to
6373ab2
Compare
It should be possible to provoke an error in the previous implementation, by:
[refack: fixed typo] |
@AndreasMadsen Here's a test for what I believe you're talking about: 'use strict';
const print = process._rawDebug;
const init_calls = { hook1: 0, hook2: 0 };
let hook2_enabled = true;
process.on('exit', () => {
require('assert').strictEqual(init_calls.hook1, init_calls.hook2);
});
const hook1 = require('async_hooks').createHook({
init(id, type) {
init_calls.hook1++;
print('hook1 init:', id, type);
if (hook2_enabled) {
hook2_enabled = false;
hook2.enable();
require('crypto').randomBytes(1024, () => {});
}
}
});
const hook2 = require('async_hooks').createHook({
init(id, type) {
init_calls.hook2++;
print('hook2 init:', id, type);
},
});
setImmediate(() => {
hook1.enable();
hook2.enable();
require('fs').open('/dev/null', 'r', (er, fd) => {});
}); This shows that init still runs for both assert.js:60
throw new errors.AssertionError({
^
AssertionError [ERR_ASSERTION]: 2 === 1
at process.on (/tmp/async-fs-init.js:8:21)
at emitOne (events.js:115:13)
at process.emit (events.js:210:7) |
@trevnorris there is a comment in the code that says: // The set of callbacks for a hook should be the same regardless of whether
// enable()/disable() are run during their execution. If I understand that comment correctly, it says that |
@AndreasMadsen Here's a more generalized test for discussion: 'use strict';
const { createHook } = require('async_hooks');
const { randomBytes } = require('crypto');
const print = process._rawDebug;
const hooks_list = [];
const start_enabled = process.argv[2] === '--start-enabled';
let cntr = -1;
for (let i = 0; i < 2; i++) {
hooks_list.push(createHook({
init(id, type) { print(`hook${i} init`); },
}));
if (start_enabled) hooks_list[hooks_list.length - 1].enable();
}
const hook = createHook({
init(id, type) {
print('hook init:', id, type);
if (++cntr < hooks_list.length) {
if (start_enabled)
hooks_list[cntr].disable();
else
hooks_list[cntr].enable();
randomBytes(1, () => {});
}
}
}).enable();
randomBytes(1, () => {}); First running without
Now running with
First thing to address is that I wouldn't expect the output for running with
As we can see from the first results table there's a strange timing issue. Namely I would have expected the output for running without
For simplicity I would interpret that comment to mean the set of callbacks from the entry point of |
First of all: I really struggle to understand what you are arguing for. Are you against this PR? If this is the case, try logging when without
You will immediately see that when Assuming you don't think this PR is wrong but something is odd about the output: In the case without The reason for this is a bug, is the use of a single flag for
On the surface, this might look fine, but what actually happens is that To put it differently, The solution as I see it, is to only let the outer without
with
I don't know why you would expect the number of called hooks to change in the "with I will create a pull request that depends on this PR and contains the additional fix I'm suggesting. |
PR #14143 contains the suggested fix. |
@BridgeAR Having spend some time debugging @trevnorris's issue I think this test better highlights the issue this PR solves: 'use strict';
const common = require('../common');
const assert = require('assert');
const async_hooks = require('async_hooks');
const crypto = require('crypto');
const nestedHook = async_hooks.createHook({
init: common.mustCall()
});
const rootHook = async_hooks.createHook({
init: common.mustCall(function (id, type) {
nestedHook.enable();
}, 2)
}).enable();
crypto.randomBytes(1, common.mustCall(function () {
crypto.randomBytes(1, common.mustCall());
})); |
@AndreasMadsen thanks a lot for the test. As you opened the follow up PR and did pretty much all work here, I could also close this one and you add the test to your PR? |
You have my permission to just copy and paste the test case I wrote. If @trevnorris thinks we should land this and #14143 together for it to make sense, then I will just rebase #14143 again. |
This fixes an error that could occure by nesting async_hooks calls
6373ab2
to
120f2e2
Compare
Rebased (I changed the commit message a bit) and incorporated. |
|
||
const common = require('../common'); | ||
const async_hooks = require('async_hooks'); | ||
const crypto = require('crypto'); |
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 you're using crypto
you need:
if (!common.hasCrypto)
common.skip('missing crypto');
AFAICT this should work with fs
or stream
...
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.
Good point, fs
should work (for example fs.access(__filename, () => {})
).
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
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.
@AndreasMadsen Thanks for the additional fix. I'm cool to land this along side your other fix.
landed in 8a83035 |
This fixes an error that could occure by nesting async_hooks calls PR-URL: #14054 Ref: #13755 (comment) Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Trevor Norris <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Andreas Madsen <[email protected]>
In some cases restoreTmpHooks is called too early, this causes active_hooks_array to change during execution of the init hooks. PR-URL: #14143 Ref: #14054 (comment) Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Trevor Norris <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
This fixes an error that could occure by nesting async_hooks calls PR-URL: #14054 Ref: #13755 (comment) Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Trevor Norris <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Andreas Madsen <[email protected]>
In some cases restoreTmpHooks is called too early, this causes active_hooks_array to change during execution of the init hooks. PR-URL: #14143 Ref: #14054 (comment) Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Trevor Norris <[email protected]> Reviewed-By: Anna Henningsen <[email protected]>
The fatalError function is overloaded to receive either an error or a string. Instead, it would be simpler to just always provide a error.Removed due to a conflict.I
alsomoved therestoreTmpHooks
call. It seemed to be more appropriate in the init function. Ref #13755 (comment)Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
async_hooks