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

repl: emit uncaughtException #20803

Closed
wants to merge 3 commits into from

Conversation

BridgeAR
Copy link
Member

@BridgeAR BridgeAR commented May 17, 2018

This was just a rough idea after looking into #19998.

I have no real opinion if this is a good idea or not and thought it might be good if others give their opinion. This way it seems like we would be able to actually report uncaughtException if a listener is attached.

If this is indeed something should could do, I'll also add tests.

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

@BridgeAR BridgeAR added wip Issues and PRs that are still a work in progress. semver-major PRs that contain breaking changes and should be released in the next major version. labels May 17, 2018
@BridgeAR BridgeAR requested a review from addaleax May 17, 2018 14:31
@nodejs-github-bot nodejs-github-bot added the repl Issues and PRs related to the REPL subsystem. label May 17, 2018
lib/repl.js Outdated
if (isError && e.stack) {
if (process.listenerCount('uncaughtException') !== 0) {
process.emit('uncaughtException', e);
} else if (isError && e.stack) {
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 want the event being emitted and information being written to stderr to be mutually exclusive? I’d generally expect that the REPL shows global errors that aren’t caught, even if there is an uncaughtException listener…

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm, to me it's similar to the "regular" error: if there's no exception listener, the app will crash. In this context it's for me printing to the repl. If the listener is attached, it should only end up there and the user has to decide what to do with it.

@apapirovski
Copy link
Member

apapirovski commented May 17, 2018

This works in the opened repl but one of the main use cases domains serve in repl is in its programmatic usage where multiple repl instances can be created. This would pretty badly break that for anyone using uncaughtException.

To me the hard part is in distinguishing which errors should go to uncaughtException and which should be written out. Everyone will have different expectations around that. I don't think just always emitting and always logging is the right answer. Not convinced it's possible to please everyone and not break anyone.

@BridgeAR
Copy link
Member Author

Is it actually possible to detect if the repl is opened or not? In that case we could just do it there?

@AyushG3112
Copy link
Contributor

The question which comes to my mind is whether we should allow one REPL session a look into uncaughtExceptions of another REPL session. I'd personally be against that as it will lead to unintended situations which would be potentially confusing to users.

@BridgeAR
Copy link
Member Author

Is there interest in trying to pursue this further? I think it would make sense in case for the opened repl in case we can distinguish that from the programmatic usage. I just do not know if we have that information / if it is possible to get that information.

@addaleax
Copy link
Member

@BridgeAR We do make some customizations for the Node.js main REPL, yes – lib/internal/repl.js is the one we use for that, rather than lib/repl.js

(Would also be okay with that, yes)

@BridgeAR
Copy link
Member Author

PTAL

I just pushed another commit that limits this functionality strictly to the very first opened repl. In case a second one is opened, it will deactivate the behavior for all.

@BridgeAR
Copy link
Member Author

@addaleax @apapirovski @AyushG3112 what do you think about the approach?

lib/repl.js Outdated Show resolved Hide resolved
lib/repl.js Outdated Show resolved Hide resolved
@jasnell
Copy link
Member

jasnell commented Oct 17, 2018

Ping @BridgeAR ... what's the status on this?

@jasnell jasnell added the stalled Issues and PRs that are stalled. label Oct 17, 2018
@BridgeAR BridgeAR changed the title WIP repl: emit uncaughtException repl: emit uncaughtException Dec 2, 2018
@BridgeAR BridgeAR removed wip Issues and PRs that are still a work in progress. stalled Issues and PRs that are stalled. labels Dec 2, 2018
@BridgeAR
Copy link
Member Author

BridgeAR commented Dec 2, 2018

CI https://ci.nodejs.org/job/node-test-pull-request/19139/

PTAL. I guess this is actually getting somewhere. I am just not to sure how to write a test for this.

@Trott
Copy link
Member

Trott commented Dec 4, 2018

@nodejs/repl This could use some reviews. Any takesr? Even someone blocking it would be more useful than it languishing with no approvals and no requests for changes, IMO.

@BridgeAR
Copy link
Member Author

BridgeAR commented Dec 5, 2018

@BridgeAR
Copy link
Member Author

@nodejs/repl @nodejs/tsc PTAL

@targos
Copy link
Member

targos commented Dec 15, 2018

@BridgeAR can you post an example repl session that shows the impact of this change?

@apapirovski
Copy link
Member

Yeah, that's fair. I'm having a look myself right now.

Copy link
Member

@apapirovski apapirovski left a comment

Choose a reason for hiding this comment

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

SGTM but is there a way to add a test?

@BridgeAR
Copy link
Member Author

I just reworked some code here due to @apapirovski request for a test because I realized that adding an uncaughtException listener in an repl instance which is not run as standalone program is going to silence all main application errors without any chance to get any kind of notification for it.

Therefore I added some more code to fix that behavior as well: it is from now on going to throw an error if the listener is added in such a case. I could theoretically move that part into a separate PR but for me it felt right here.

While writing tests I also noticed that the former way of detecting if the REPL was run as standalone program or not was not sufficient. Currently there's no way to detect if it's the internal repl or not, so I added an internal symbol to detect that as well.

Therefore I'll ask everyone who had a look at this so far to take another look. Thanks.

@BridgeAR BridgeAR mentioned this pull request Jan 27, 2019
4 tasks
@BridgeAR
Copy link
Member Author

CI https://ci.nodejs.org/job/node-test-pull-request/20347/

@nodejs/tsc PTAL as this is now also fixing a nasty "bug" that could be triggered when using uncaughtException in the repl (silencing the main application errors).

doc/api/errors.md Outdated Show resolved Hide resolved
doc/api/repl.md Outdated Show resolved Hide resolved
@Trott
Copy link
Member

Trott commented Jan 27, 2019

Since it's semver-major, should we run CITGM at this time?

lib/internal/errors.js Outdated Show resolved Hide resolved
lib/internal/repl.js Outdated Show resolved Hide resolved
lib/repl.js Show resolved Hide resolved
@addaleax
Copy link
Member

Since it's semver-major, should we run CITGM at this time?

I don’t think we have modules in CITGM that test the default REPL (aka Node’s “interactive” mode) in any way, so I’m not sure it’s worth it?

Adding an `uncaughtException` listener in an REPL instance suppresses
errors in the whole application.
Closing the instance won't remove those listeners either.
The internal default repl will from now on trigger `uncaughtException`
handlers instead of ignoring them. The regular error output is
suppressed in that case.
@BridgeAR
Copy link
Member Author

BridgeAR commented Apr 7, 2019

I updated the PR and incorporated the feedback. I also added a known issue test that highlights one of the problems this PR partially fixes (using the uncaughtException listener from an REPL instance silences all errors in the application that started that instance).

PTAL

@nodejs-github-bot
Copy link
Collaborator

@BridgeAR
Copy link
Member Author

BridgeAR commented Apr 9, 2019

Superseded by #27151

I found a way to also handle the async cases properly and this PR changed multiple times, so it felt better to open a new one instead of keeping this one around.

@BridgeAR BridgeAR closed this Apr 9, 2019
Copy link
Member

@lance lance left a comment

Choose a reason for hiding this comment

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

I was a little late on the review here. But I will submit it anyway. It's been sitting unsubmitted in my browser for a couple of days.

<a id="ERR_INVALID_REPL_INPUT"></a>
### ERR_INVALID_REPL_INPUT

The input can or may not be used in the [`REPL`][]. All prohibited inputs are
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 understand what is meant by "can or may not be used".

Copy link
Member Author

Choose a reason for hiding this comment

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

I thought I'll keep it broad so that it could be used for different REPL input. So far it will only be used for uncaught exception listeners, so only the may part applies. I am happy to change it to only may or what ever you have as alternative.

* Uncaught exceptions do not emit the [`'uncaughtException'`][] event.
* Uncaught exceptions only emit the [`'uncaughtException'`][] event if the
`repl` is used as standalone program. If the `repl` is included anywhere in
another application, adding this event synchronous will throw an
Copy link
Member

Choose a reason for hiding this comment

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

What is meant by "adding this event synchronous"?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is actually outdated in the other PR. In this version I was not able to actually handle listeners that were added asynchronously. E.g., setTimeout(() => process.on("uncaughtException", () => {})) was not detected here. This is fixed in the latest implementation.


```js
process.on('uncaughtException', () => console.log('Uncaught'));
// TypeError [ERR_INVALID_REPL_INPUT]: Unhandled exception listeners can not be
Copy link
Member

Choose a reason for hiding this comment

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

Nit: perhaps "Listeners for uncaughtException cannot be used in the REPL" is a bit clearer.

@@ -40,8 +39,6 @@ process.on('uncaughtException', (e) => {
throw e;
});

process.on('exit', () => (Error.prepareStackTrace = origPrepareStackTrace));
Copy link
Member

Choose a reason for hiding this comment

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

This seems unrelated to the PR changes. What am I missing?

Copy link
Member Author

Choose a reason for hiding this comment

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

It is somewhat unrelated. In a former PR this test was impacted as well and I noticed that this is actually not necessary, so I just went ahead and removed it.

@BridgeAR BridgeAR deleted the repl-add-uncaught-exception branch January 20, 2020 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
repl Issues and PRs related to the REPL subsystem. semver-major PRs that contain breaking changes and should be released in the next major version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.