-
-
Notifications
You must be signed in to change notification settings - Fork 34.6k
repl: remove dependency on domain module #61227
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -736,6 +736,42 @@ generate a core file. | |
|
|
||
| This feature is not available in [`Worker`][] threads. | ||
|
|
||
| ## `process.addUncaughtExceptionCaptureCallback(fn)` | ||
|
|
||
| <!-- YAML | ||
| added: REPLACEME | ||
| --> | ||
|
|
||
| * `fn` {Function} | ||
|
|
||
| The `process.addUncaughtExceptionCaptureCallback()` function adds a callback | ||
| that will be invoked when an uncaught exception occurs, receiving the exception | ||
| value as its first argument. | ||
|
|
||
| Unlike [`process.setUncaughtExceptionCaptureCallback()`][], this function allows | ||
| multiple callbacks to be registered and does not conflict with the | ||
| [`domain`][] module. Callbacks are called in reverse order of registration | ||
| (most recent first). If a callback returns `true`, subsequent callbacks | ||
| and the default uncaught exception handling are skipped. | ||
|
|
||
| ```mjs | ||
| import process from 'node:process'; | ||
|
|
||
| process.addUncaughtExceptionCaptureCallback((err) => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Won't it be available on global |
||
| console.error('Caught exception:', err.message); | ||
| return true; // Indicates exception was handled | ||
| }); | ||
| ``` | ||
|
|
||
| ```cjs | ||
| const process = require('node:process'); | ||
|
|
||
| process.addUncaughtExceptionCaptureCallback((err) => { | ||
| console.error('Caught exception:', err.message); | ||
| return true; // Indicates exception was handled | ||
| }); | ||
| ``` | ||
|
|
||
| ## `process.allowedNodeEnvironmentFlags` | ||
|
|
||
| <!-- YAML | ||
|
|
@@ -4038,8 +4074,8 @@ To unset the capture function, | |
| method with a non-`null` argument while another capture function is set will | ||
| throw an error. | ||
|
|
||
| Using this function is mutually exclusive with using the deprecated | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we should add this to |
||
| [`domain`][] built-in module. | ||
| To register multiple callbacks that can coexist, use | ||
| [`process.addUncaughtExceptionCaptureCallback()`][] instead. | ||
|
|
||
| ## `process.sourceMapsEnabled` | ||
|
|
||
|
|
@@ -4571,6 +4607,7 @@ cases: | |
| [`net.Socket`]: net.md#class-netsocket | ||
| [`os.constants.dlopen`]: os.md#dlopen-constants | ||
| [`postMessageToThread()`]: worker_threads.md#worker_threadspostmessagetothreadthreadid-value-transferlist-timeout | ||
| [`process.addUncaughtExceptionCaptureCallback()`]: #processadduncaughtexceptioncapturecallbackfn | ||
| [`process.argv`]: #processargv | ||
| [`process.config`]: #processconfig | ||
| [`process.execPath`]: #processexecpath | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||
| 'use strict'; | ||||||
|
|
||||||
| const { | ||||||
| ArrayPrototypePush, | ||||||
| RegExpPrototypeExec, | ||||||
| StringPrototypeIndexOf, | ||||||
| StringPrototypeSlice, | ||||||
|
|
@@ -105,15 +106,18 @@ function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) { | |||||
| } | ||||||
|
|
||||||
| const exceptionHandlerState = { | ||||||
| captureFn: null, | ||||||
| captureFn: null, // Primary callback (for domain's exclusive use) | ||||||
| auxiliaryCallbacks: [], // Auxiliary callbacks (for REPL, etc.) - always called | ||||||
| reportFlag: false, | ||||||
| }; | ||||||
|
|
||||||
| function setUncaughtExceptionCaptureCallback(fn) { | ||||||
| if (fn === null) { | ||||||
| exceptionHandlerState.captureFn = fn; | ||||||
| shouldAbortOnUncaughtToggle[0] = 1; | ||||||
| process.report.reportOnUncaughtException = exceptionHandlerState.reportFlag; | ||||||
| if (exceptionHandlerState.auxiliaryCallbacks.length === 0) { | ||||||
| shouldAbortOnUncaughtToggle[0] = 1; | ||||||
| process.report.reportOnUncaughtException = exceptionHandlerState.reportFlag; | ||||||
| } | ||||||
| return; | ||||||
| } | ||||||
| if (typeof fn !== 'function') { | ||||||
|
|
@@ -129,6 +133,23 @@ function setUncaughtExceptionCaptureCallback(fn) { | |||||
| process.report.reportOnUncaughtException = false; | ||||||
| } | ||||||
|
|
||||||
| // Add an auxiliary callback that coexists with the primary callback. | ||||||
| // Auxiliary callbacks are called first; if any returns true, the error is handled. | ||||||
| // Otherwise, the primary callback (if set) is called. | ||||||
| function addUncaughtExceptionCaptureCallback(fn) { | ||||||
| if (typeof fn !== 'function') { | ||||||
| throw new ERR_INVALID_ARG_TYPE('fn', 'Function', fn); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| } | ||||||
| if (exceptionHandlerState.auxiliaryCallbacks.length === 0 && | ||||||
| exceptionHandlerState.captureFn === null) { | ||||||
| exceptionHandlerState.reportFlag = | ||||||
| process.report.reportOnUncaughtException === true; | ||||||
| process.report.reportOnUncaughtException = false; | ||||||
| shouldAbortOnUncaughtToggle[0] = 0; | ||||||
| } | ||||||
| ArrayPrototypePush(exceptionHandlerState.auxiliaryCallbacks, fn); | ||||||
| } | ||||||
|
|
||||||
| function hasUncaughtExceptionCaptureCallback() { | ||||||
| return exceptionHandlerState.captureFn !== null; | ||||||
| } | ||||||
|
|
@@ -154,21 +175,33 @@ function createOnGlobalUncaughtException() { | |||||
|
|
||||||
| const type = fromPromise ? 'unhandledRejection' : 'uncaughtException'; | ||||||
| process.emit('uncaughtExceptionMonitor', er, type); | ||||||
| // Primary callback (e.g., domain) has priority and always handles the exception | ||||||
| if (exceptionHandlerState.captureFn !== null) { | ||||||
| exceptionHandlerState.captureFn(er); | ||||||
| } else if (!process.emit('uncaughtException', er, type)) { | ||||||
| // If someone handled it, then great. Otherwise, die in C++ land | ||||||
| // since that means that we'll exit the process, emit the 'exit' event. | ||||||
| try { | ||||||
| if (!process._exiting) { | ||||||
| process._exiting = true; | ||||||
| process.exitCode = kGenericUserError; | ||||||
| process.emit('exit', kGenericUserError); | ||||||
| } else { | ||||||
| // If no primary callback, try auxiliary callbacks (e.g., REPL) | ||||||
| // They must return true to indicate handling | ||||||
| let handled = false; | ||||||
| for (let i = exceptionHandlerState.auxiliaryCallbacks.length - 1; i >= 0; i--) { | ||||||
| if (exceptionHandlerState.auxiliaryCallbacks[i](er) === true) { | ||||||
| handled = true; | ||||||
| break; | ||||||
| } | ||||||
| } | ||||||
| if (!handled && !process.emit('uncaughtException', er, type)) { | ||||||
| // If someone handled it, then great. Otherwise, die in C++ land | ||||||
| // since that means that we'll exit the process, emit the 'exit' event. | ||||||
| try { | ||||||
| if (!process._exiting) { | ||||||
| process._exiting = true; | ||||||
| process.exitCode = kGenericUserError; | ||||||
| process.emit('exit', kGenericUserError); | ||||||
| } | ||||||
| } catch { | ||||||
| // Nothing to be done about it at this point. | ||||||
| } | ||||||
| } catch { | ||||||
| // Nothing to be done about it at this point. | ||||||
| return false; | ||||||
| } | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| // If we handled an error, then make sure any ticks get processed | ||||||
|
|
@@ -477,5 +510,6 @@ module.exports = { | |||||
| evalScript, | ||||||
| onGlobalUncaughtException: createOnGlobalUncaughtException(), | ||||||
| setUncaughtExceptionCaptureCallback, | ||||||
| addUncaughtExceptionCaptureCallback, | ||||||
| hasUncaughtExceptionCaptureCallback, | ||||||
| }; | ||||||
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.
Should we land it as experimental first?