-
-
Notifications
You must be signed in to change notification settings - Fork 533
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
is loaded unconditionally, preventing uncaught exception capture
#2024
Comments
As far as I can tell, everything that uses the repl loads it from |
Is this a node bug? Is Reminds me of #1587 (comment) |
Well, yes, it is, but it's more that it uses domains, and domains trigger side effects. Refactoring repl to not use domains is on the todo list, I believe, but not super high priority. If there's a way to not |
Also, if node 16 (or even 18) support is intended, then there's really no way around repl being domain based. There's no way that'll be back ported. Even fixing in node v20 is pretty unlikely. So, if this can't be addressed in ts-node, I probably need to find (or more likely, write) an alternative |
Fair enough, we do want to support node 16 and 18 until they're EOLed. I'm still confused why I think the only things we use from It looks like we lazy-load source-map-support so might be as simple as copy-pasting that pattern, but really any pattern sounds fine. Line 6 in 7af5c48
Line 694 in 7af5c48
|
brief history of domainsIn 2011, before a spec for Promise semantics were universally accepted, let alone a first class part of the language, we in Node were really feeling the shortcomings of callback- and eventemitter-based programming for larger scale systems. There was Ryan Dahl had a very nebulous idea for a way to group a family of event emitters, async requests, handles, and timers, whereby anything spawned from something in a given group would be a part of that group, and the user could arbitrarily start a new group as a child of the current one. He spent the better part of a year talking, writing, and discussing this idea, and generally getting people pretty excited about how it would solve what was then one of the most pressing issues in node. Then, he quit the project, and left Node to become a professional hipster for a while, and tossed the keys to me on the way out. We on the core team (and I personally) felt the need to deliver something that would make good on these promises, and it seemed like a good and useful idea. The problem was that there wasn't really a clear specification, and everyone had very different ideas about exactly what domains were supposed to do or how they were supposed to behave. After a few months of whittling this down to something more cohesive, we were left with a choice. Do it right, which would be a lot of threading through libuv's timers and the V8 engine and so forth, or just throw something together that would check all the boxes. And the spec that emerged was something that could clearly be done in userland with the tools we had, just by adding some hooks in the JS layer EventEmitter class and process object. Since it was just an experiment, and we figured it'd end up being scrapped and built properly soon anyway, we went that direction, and shipped it. The problem with the design immediately became obvious. EventEmitter is used everywhere in node, and adding tracking behavior to every We couldn't just rip it out though, mostly because New Relic, then one of Node's biggest and most vocal proponents, built their whole APM node client on top of it, and there wasn't really any alternative. (There were a few others as well, experimental stuff got relied on a lot more casually back then.) That alternative came (for APM at least) with Isolates (and the advent of async/await, and node's consistent painstaking use of primordials) addressed most of the other issues that domains were intended to alleviate, and afaik, repl's reliance on domain is one of the last reasons why it's still around. |
PR coming shortly! |
Actually starting the repl will still put the process into domain-mode, but this at least allows programs to use `ts-node` or `--loader=ts-node/esm` without losing the ability to use process.setUncaughtExceptionCaptureCallback(). The problem should ideally be fixed (or mitigated) in node core, but this is still worthwhile for the benefit of supporting current node versions. Re: nodejs/node#48131 Fix: TypeStrong#2024
Actually starting the repl will still put the process into domain-mode, but this at least allows programs to use `ts-node` or `--loader=ts-node/esm` without losing the ability to use process.setUncaughtExceptionCaptureCallback(). The problem should ideally be fixed (or mitigated) in node core, but this is still worthwhile for the benefit of supporting current node versions. Re: nodejs/node#48131 Fix: TypeStrong#2024
* fix: lazy-load repl to avoid domain side effects Actually starting the repl will still put the process into domain-mode, but this at least allows programs to use `ts-node` or `--loader=ts-node/esm` without losing the ability to use process.setUncaughtExceptionCaptureCallback(). The problem should ideally be fixed (or mitigated) in node core, but this is still worthwhile for the benefit of supporting current node versions. Re: nodejs/node#48131 Fix: #2024 * Update src/repl.ts --------- Co-authored-by: Andrew Bradley <cspotcode@gmail.com>
Search Terms
Expected Behavior
Should be able to use the
process.setUncaughtExceptionCaptureCallback()
method in programs loaded using thets-node/esm
loader.Actual Behavior
Use of
process.setUncaughtExceptionCaptureCallback()
will trigger the following error in ts-node programs if an uncaught exception occurs, making it impossible to use node's officially sanctioned global error handling mechanism. Rather than reporting the error that was thrown, you get a much less useful crash report like this:Steps to reproduce the problem
Expected behavior:
Actual behavior:
(Same behavior with
ts-node ts-node-uncaught-exception-handler-error.ts
.)Minimal reproduction
see above
The path to requiring
node:domain
is:const esm = require('./dist/esm');
src/esm.ts
)import { register, RegisterOptions, Service } from './index';
export { createRepl, CreateReplOptions, ReplService, EvalAwarePartialHost } from './repl';
const domain = require('domain');
Suggestion: require
./repl
lazily, since it is rarely needed, and has this rather unfortunate side effect.Specifications
Operating system and version: Darwin moxy.lan 22.4.0 Darwin Kernel Version 22.4.0: Mon Mar 6 20:59:28 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T6000 arm64
If Windows, are you using WSL or WSL2?: N/A
The text was updated successfully, but these errors were encountered: