Skip to content

Commit

Permalink
promise: emit error on domain unhandled rejections
Browse files Browse the repository at this point in the history
PR-URL: #36082
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Yongsheng Zhang <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
  • Loading branch information
benjamingr authored and codebytere committed Nov 22, 2020
1 parent 89da0c3 commit eb9295b
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 33 deletions.
22 changes: 14 additions & 8 deletions lib/internal/process/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ function unhandledRejection(promise, reason) {
maybeUnhandledPromises.set(promise, {
reason,
uid: ++lastPromiseId,
warned: false
warned: false,
domain: process.domain
});
// This causes the promise to be referenced at least for one tick.
pendingUnhandledRejections.push(promise);
Expand Down Expand Up @@ -192,26 +193,32 @@ function processPromiseRejections() {
}
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);
}
switch (unhandledRejectionsMode) {
case kStrictUnhandledRejections: {
const err = reason instanceof Error ?
reason : generateUnhandledRejectionError(reason);
triggerUncaughtException(err, true /* fromPromise */);
const handled = process.emit('unhandledRejection', reason, promise);
const handled = emit(reason, promise, promiseInfo);
if (!handled) emitUnhandledRejectionWarning(uid, reason);
break;
}
case kIgnoreUnhandledRejections: {
process.emit('unhandledRejection', reason, promise);
emit(reason, promise, promiseInfo);
break;
}
case kAlwaysWarnUnhandledRejections: {
process.emit('unhandledRejection', reason, promise);
emit(reason, promise, promiseInfo);
emitUnhandledRejectionWarning(uid, reason);
break;
}
case kThrowUnhandledRejections: {
const handled = process.emit('unhandledRejection', reason, promise);
const handled = emit(reason, promise, promiseInfo);
if (!handled) {
const err = reason instanceof Error ?
reason : generateUnhandledRejectionError(reason);
Expand All @@ -220,7 +227,7 @@ function processPromiseRejections() {
break;
}
case kWarnWithErrorCodeUnhandledRejections: {
const handled = process.emit('unhandledRejection', reason, promise);
const handled = emit(reason, promise, promiseInfo);
if (!handled) {
emitUnhandledRejectionWarning(uid, reason);
process.exitCode = 1;
Expand Down Expand Up @@ -266,10 +273,9 @@ function generateUnhandledRejectionError(reason) {
function listenForRejections() {
setPromiseRejectCallback(promiseRejectHandler);
}

module.exports = {
hasRejectionToWarn,
setHasRejectionToWarn,
listenForRejections,
processPromiseRejections
processPromiseRejections,
};
10 changes: 10 additions & 0 deletions test/parallel/test-domain-promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,13 @@ process.on('warning', common.mustNotCall());
}));
}));
}
{
// Unhandled rejections become errors on the domain
const d = domain.create();
d.on('error', common.mustCall((e) => {
assert.strictEqual(e.message, 'foo');
}));
d.run(common.mustCall(() => {
Promise.reject(new Error('foo'));
}));
}
25 changes: 0 additions & 25 deletions test/parallel/test-promises-unhandled-rejections.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const domain = require('domain');
const { inspect } = require('util');

common.disableCrashOnUnhandledRejection();
Expand Down Expand Up @@ -622,30 +621,6 @@ asyncTest('setImmediate + promise microtasks is too late to attach a catch' +
});
});

asyncTest(
'Promise unhandledRejection handler does not interfere with domain' +
' error handlers being given exceptions thrown from nextTick.',
function(done) {
const d = domain.create();
let domainReceivedError;
d.on('error', function(e) {
domainReceivedError = e;
});
d.run(function() {
const e = new Error('error');
const domainError = new Error('domain error');
onUnhandledSucceed(done, function(reason, promise) {
assert.strictEqual(reason, e);
assert.strictEqual(domainReceivedError, domainError);
});
Promise.reject(e);
process.nextTick(function() {
throw domainError;
});
});
}
);

asyncTest('nextTick is immediately scheduled when called inside an event' +
' handler', function(done) {
clean();
Expand Down

0 comments on commit eb9295b

Please sign in to comment.