Skip to content
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: execute unhandledRejection cb in Promise execution context #37281

Closed
wants to merge 1 commit into from

Conversation

sajal50
Copy link
Contributor

@sajal50 sajal50 commented Feb 8, 2021

This commit now executes process.on('unhandledRejection') in the
async execution context of the concerned Promise.

Fixes #37244

@nodejs-github-bot nodejs-github-bot added async_hooks Issues and PRs related to the async hooks subsystem. c++ Issues and PRs that require attention from people who are familiar with C++. process Issues and PRs related to the process subsystem. labels Feb 8, 2021
// throw new Error('Throwing on purpose');
// });

Promise.reject();
Copy link
Contributor Author

@sajal50 sajal50 Feb 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@benjamingr I noticed an interesting case. If you just do Promise.reject the async_hooks.executionAsyncId() is incorrect in process.on('unhandledRejection')'s callback. But it is correct if you do,

Promise.resolve()
.then(() => {
   throw new Error('Throwing on purpose');
 });

Therefore, I tried out setting the context in node_task_queue, and then it seems to be correct.

Let me know your thoughts.

: v8::Just(AsyncWrap::kInvalidAsyncId);
}
else {
return Nothing<double>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You generally don't want to return a Nothing<> unless there's an exception pending (because that's what it means)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can probably return v8::Just(AsyncWrap::kInvalidAsyncId); here too ?

GetAssignedPromiseWrapAsyncId(env, promise, env->async_id_symbol())
.To(&async_id);
GetAssignedPromiseWrapAsyncId(env, promise, env->trigger_async_id_symbol())
.To(&trigger_async_id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These calls can lead to JS exceptions, so I think you want to move all of this into the TryCatchScope here and return if any of these .To() calls return false

}

if (try_catch_async_id.HasCaught()) {
// What must be done here?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What must we do here? I don't imagine this should throw. Shall we print like it's done below?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think we’ll get to this point here, because now we’re already returning early whenever an exception happens.

You can remove this conditional (and remove the second TryCatchScope, it’s okay to have a single one)

@sajal50
Copy link
Contributor Author

sajal50 commented Feb 9, 2021

@addaleax @benjamingr Thank you both for the feedback.
I've addressed it. I have one open question.

Also, I am opening this PR from draft to run CI.

@sajal50 sajal50 marked this pull request as ready for review February 9, 2021 03:18
This commit now executes `process.on('unhandledRejection')` in the
async execution context of the concerned `Promise`.
@nodejs-github-bot
Copy link
Collaborator

if (async_id == AsyncWrap::kInvalidAsyncId &&
trigger_async_id == AsyncWrap::kInvalidAsyncId) {
// That means that promise might be a PromiseWrap, so we'll
// check there as well.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add tests for both cases here?

Copy link
Contributor Author

@sajal50 sajal50 Feb 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually manually ran the other case by commenting this line out while running the test case added in this PR. It passed.

However, I guess we can change ActivityCollector to not use a noop function when ondestroy is not provided. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why the test would need to use ActivityCollector, or be in test/async-hooks -- a lot of async_hooks tests that don't make use of the special features that that subdirectory has are just in test/parallel.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. What are these "special features" out of curiosity?

Also, if I just assumed initHooks had convenient methods when dealing with async hooks. What is otherwise the purpose?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these "special features" out of curiosity?

Things like ActivityCollector, and the rest that’s in async-hooks/init-hooks.js and async-hooks/hook-checks.js.

Also, if I just assumed initHooks had convenient methods when dealing with async hooks. What is otherwise the purpose?

They do, but it’s not like you have to use them. At least for the test here, the difference to using async hooks directly seems to be relatively small.

@sajal50
Copy link
Contributor Author

sajal50 commented Feb 9, 2021

Also, are these CI failures due to flakiness?

@nodejs-github-bot
Copy link
Collaborator

@sajal50
Copy link
Contributor Author

sajal50 commented Feb 9, 2021

@addaleax @benjamingr

I guess one check still fails. Let me know if it can be ignored.

Also, will wait for your guidance on this.

@sajal50
Copy link
Contributor Author

sajal50 commented Feb 11, 2021

Polite 🔔
@addaleax @benjamingr

@benjamingr
Copy link
Member

I'm fine with this landing but I want Anna to respond regarding the test question :)

If she doesn't and a week passes this can just land.

@addaleax
Copy link
Member

Yeah, I'm good here, although I still think it would be good to cover both variants here. If it turns our to be hard to write a test then leaving a TODO comment about that might be fine.

@benjamingr benjamingr added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Feb 13, 2021
benjamingr pushed a commit that referenced this pull request Feb 13, 2021
This commit now executes `process.on('unhandledRejection')` in the
async execution context of the concerned `Promise`.

PR-URL: #37281
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
@benjamingr
Copy link
Member

Landed in 7d5806e - thank you for contributing and bearing with us @sajal50

@sajal50
Copy link
Contributor Author

sajal50 commented Feb 13, 2021

Thank you, both. :)
I'll address @addaleax's concern in a follow up PR.

danielleadams pushed a commit that referenced this pull request Feb 16, 2021
This commit now executes `process.on('unhandledRejection')` in the
async execution context of the concerned `Promise`.

PR-URL: #37281
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This was referenced Feb 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
async_hooks Issues and PRs related to the async hooks subsystem. author ready PRs that have at least one approval, no pending requests for changes, and a CI started. c++ Issues and PRs that require attention from people who are familiar with C++. process Issues and PRs related to the process subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

asyncId for unhandled rejected Promise
5 participants