-
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
src: exit on gc unhandled rejection #20097
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
lib/internal/bootstrap/node.js
Outdated
@@ -426,23 +426,23 @@ | |||
emitAfter | |||
} = NativeModule.require('internal/async_hooks'); | |||
|
|||
process._fatalException = function(er) { | |||
process._fatalException = function(er, fromPromise) { |
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.
The only point of fromPromise
is skipping the uncaughtException
handler – is that correct? If so, can you explain the motivation behind it?
(Also, if that is correct: Could we name it something like skipUncaughtExceptionListener
or so, to be a bit more descriptive?)
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 is correct. In this case I just used the original implementation. I personally have no strong opinion about having a uncaughtException
in this case. In a way it would make sense to have 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.
I'm +1 on calling uncaughtException
handlers on unhandled rejections. I think it would be very surprising to not have them called - especially for APMs.
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.
Note that this would also mean we'd have to deal with the case people chose to ignore the error rather than exit the process - like they can in an "unhandledRejection"
handler.
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 +1 to route unhandled rejection into 'uncaughtException'
at this point.
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.
@ljharb that would not be possible with the suggested implementation. What could be done is to wrap the error into another error that reports about being a unhandled rejection.
@benjamingr that would not be the case with the suggested change. It would work as I explained above. So having a unhandledRejection
handler will not prevent the process to exit. That would completely depend on uncaughtException
.
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.
@BridgeAR I understand and I don't think that's correct semantics. I think it would surprise users - you'd expect to be able to intercept any unhandledRejection
. It's very common to use it to throw
and cause the uncaughtException
today - or suppress termination in certain cases like:
process.on('unhandledRejection', err => {
if (err.isImportant) log(err);
if (err.isSpecificKind) return; // not an error, a bug with some library I'm using
throw err;
});
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 is possible to intercept the unhandled rejections. But the error on GC is a different story.
By the way: without routing the unhandled rejection to uncaught exception, it would not be possible to stop the process from exiting.
It is a anti pattern to continue the program in case a exception is thrown. The pattern about ignoring specific errors is not something we should promote out of my perspective. In case a library is handling something wrong, the library should be fixed or not used.
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
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.
To anyone reading - we went on to gather some real user data and the contents of this thread is invalid. See the proposed semantics in nodejs/promise-use-cases#27
It appears to me that this has hole that original doesn't: The information gets lots entirely if your process exists prematurely. Even if the promise remains unhandled to process end. That's why I did iteration on process end to check if there were unhandled rejections lying around. GC on promises is so slow that it is only likely to trigger on long-running applications, even if silent error(s) occurred and state is undefined in shorter scripts. |
I suppose that could be done separately, but it seems deeply connected to the end behavior to me. |
f9bcf1c
to
333b0fb
Compare
@Fishrock123 |
I addressed some comments. |
Just a heads up: I am currently flooded and I am going to work on this in one or two days again. |
@BridgeAR what's your thought on the suggestion that this be landed as experimental to start? It seems like it might make sense to me. |
The current plan is to land this as opt-in to start with users having to explicitly define an environment variable or use a command-line flag. The idea is to change this behaviour to the default at a later point. |
|
||
Setting this environment variable allows fine grained control over the behavior | ||
of unhandled rejections. This may be set to either one of `SILENT`, `WARN`, | ||
`ERROR_ON_GC`, `ERROR` or `STRICT` while the default behavior without using the |
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 a nit... make the values lower-case. They tend to be easier for users. --unhandled-rejections=error_on_gc
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.
They will be accepted in all cases but it should be easier to read them being upper case.
It should have received a variable. Instead, it was set to a string that was coerced to a integer later on. This fixes it by correctly passing through the variable value.
This adds a fast path to the unhandledRejections and handledRejections to actually stop trying to emit something if no hook is attached.
It is not necessary to run the microtasks when an unhandledRejection hook is attached.
fixup: undo deprecation change
77b2bcf
to
637824f
Compare
Ping @BridgeAR ... given the discussion last week, do you plan on updating this PR or opening a new one with the agreed upon updates? |
I am fine either way. I would likely just go ahead and update the PR. |
Can someone summarize what updates were agreed upon? |
@ljharb we agreed to move forward on a silent mode, warning mode, and always exit mode. however four people (including myself) disagreed with the existence of gc mode, and no one in the room could think of any good reason why anyone would want to use a gc mode. i don't recall though if we agreed on a default... maybe it happened after the zoom cut out. |
Add an opt-in flag to let the user choose between 3 ways for Node to react to unhandled rejections:
|
Actually, when @BridgeAR asked us who disagreed with Exit on GC there were more than 4 people with their hands up.
We agreed that default is out of scope for this PR and should be discussed separately. |
@mmarchini thanks for the correction, i'm glad it was more :) |
Dear Santa, I haven't written in awhile, sorry. I found myself at this PR after clicking through three previously-closed PRs all the way back to April 2016. Then I read through nodejs/promises#26, where it sounded like abort-on-GC was accepted as a fair solution. A full two years later, when this PR was opened, it was still a fair solution. Now, I'm reading Node.js need a flag to choose between three behaviors; one of which is the current behavior, another is seemingly the same as This is comically frustrating. If collaborators can't even agree on which behavior(s) to provide, how could they pick a default? So here's my xmas list. I realize this is a big ask.
your servant in darkness, P.S. If I don't drop dead from embarrassment, you will find milk & cookies on the counter next to the whiskey and aspirin. |
I opened a alternative PR: #26599 |
This is a minimal implementation of exiting on garbage collected unhandled rejections.
As soon as a unhandled rejection is collected, it will trigger a fatal exception and exit with code 1 and print the error.
It will keep emitting warnings as it used to to and the user will be notified in case there are false negatives for the GC (a truly unhandled rejection is not garbage collected).
The warnings have quite some room for performance optimization but I wanted to keep this PR to the bare minimum so it is only about the functionality itself. I plan on working on optimizing the performance after this landed.
This work is based on former work from @Fishrock123 and @addaleax.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes