-
Notifications
You must be signed in to change notification settings - Fork 30k
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
asyncId for unhandled rejected Promise #37244
Comments
Hmm, I vaguely recall fixing this for domains at some point so the REPL doesn't crash. This shouldn't be too hard to address. @sajal50 if I may ask - whay are you using the asyncId for in the |
Effectively the idea is that there our different "entities" running in a single process creating Promises as they see fit. If one of those entities has an unhanded promise rejection I wish to know which entity caused it and take appropriate action like cleaning up the entity. I don't wish the other entities to be affected and terminate the process. |
I don't think that's safe since the entities can (and probably do) leak things that are "global" in the Node.js process, we should do a better job documenting that. That said - this sounds like a bug that should be fixed regardless. The fix should be pretty simple: we have a pool and when we do cc @nodejs/async_hooks Also cc @Linkgoron in case you want to work on this |
I agree. My example perhaps was not the best. Just think it'd still be useful.
I would love to take a crack at this. Can try building this weekend and get back. Thanks for the guidance. :) |
Assigned to you in the meantime :] Please check out the docs part where it talks about resource pools (I think worker pools are the example used) and the code for making |
Sorry, where is this doc exactly? |
Alright. Thanks, @benjamingr. Will take a look. |
A simple solution could look something like (I haven't tested): diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js
index 023f7df036..8fed595bb9 100644
--- a/lib/internal/process/promises.js
+++ b/lib/internal/process/promises.js
@@ -24,6 +24,8 @@ const {
triggerUncaughtException
} = internalBinding('errors');
+const asyncHooks = require('async_hooks');
+
// *Must* match Environment::TickInfo::Fields in src/env.h.
const kHasRejectionToWarn = 1;
@@ -116,11 +118,18 @@ function resolveError(type, promise, reason) {
}
function unhandledRejection(promise, reason) {
+ const emit = asyncHooks.bind((reason, promise, promiseInfo) => {
+ if (promiseInfo.domain) {
+ return promiseInfo.domain.emit('error', reason);
+ }
+ return process.emit('unhandledRejection', reason, promise);
+ });
maybeUnhandledPromises.set(promise, {
reason,
uid: ++lastPromiseId,
warned: false,
- domain: process.domain
+ domain: process.domain,
+ emit
});
// This causes the promise to be referenced at least for one tick.
ArrayPrototypePush(pendingUnhandledRejections, promise);
@@ -194,13 +203,7 @@ function processPromiseRejections() {
continue;
}
promiseInfo.warned = true;
- const { reason, uid } = promiseInfo;
- function emit(reason, promise, promiseInfo) {
- if (promiseInfo.domain) {
- return promiseInfo.domain.emit('error', reason);
- }
- return process.emit('unhandledRejection', reason, promise);
- }
+ const { reason, uid, emit } = promiseInfo;
switch (unhandledRejectionsMode) {
case kStrictUnhandledRejections: {
const err = reason instanceof Error ? |
Hmm, this doesn't work.
I was trying to follow this. I thought I could extract UPDATE: Perhaps you meant |
diff --git a/lib/internal/process/promises.js b/lib/internal/process/promises.js
index 023f7df036..0e5d1181cb 100644
--- a/lib/internal/process/promises.js
+++ b/lib/internal/process/promises.js
@@ -24,6 +24,9 @@ const {
triggerUncaughtException
} = internalBinding('errors');
+const { async_id_symbol,
+ trigger_async_id_symbol } = internalBinding('symbols');
+
// *Must* match Environment::TickInfo::Fields in src/env.h.
const kHasRejectionToWarn = 1;
@@ -120,7 +123,8 @@ function unhandledRejection(promise, reason) {
reason,
uid: ++lastPromiseId,
warned: false,
- domain: process.domain
+ domain: process.domain,
+ asyncId: promise[async_id_symbol]
});
// This causes the promise to be referenced at least for one tick.
ArrayPrototypePush(pendingUnhandledRejections, promise);
@@ -194,12 +198,12 @@ function processPromiseRejections() {
continue;
}
promiseInfo.warned = true;
- const { reason, uid } = promiseInfo;
+ const { reason, uid, asyncId } = promiseInfo;
function emit(reason, promise, promiseInfo) {
if (promiseInfo.domain) {
return promiseInfo.domain.emit('error', reason);
}
- return process.emit('unhandledRejection', reason, promise);
+ return process.emit('unhandledRejection', reason, promise, asyncId);
}
switch (unhandledRejectionsMode) {
case kStrictUnhandledRejections: { I had this working. Basically, I see |
Yeah |
@benjamingr But doesn't that lead to a new At least with this draft change I am able to get the correct UPDATE: |
So, I was able to make this commit work. I get the correct I can raise a draft PR if this a decent starting point to discuss further. |
@sajal50 I think this looks good, honestly the only thing missing here is a test :] |
Oh, that's awesome. 😃 I am not super familiar with node's code organization. Do I just add the test case as a new file in https://github.com/nodejs/node/tree/master/test/async-hooks? |
@sajal50 probably just add to |
Fixed in #37281 (comment) - thank you for contributing a fix :] |
Is your feature request related to a problem? Please describe.
I am trying to track the lifecycle events of a
Promise
. Withasync_hooks
I am able to get those and eachPromise
is assigned anasyncId
. However, I wish to know theasyncId
of aPromise
that was rejected and didn't have acatch
handler attached to it. I see that with there isprocess.on('unhandledRejection')
, but I don't believe that can give that info.Describe the solution you'd like
A way to be informed of the
asyncId
for an unhandledPromise
.The text was updated successfully, but these errors were encountered: