-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
Implement unhandled rejection tracking #758
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 |
---|---|---|
|
@@ -31,6 +31,7 @@ | |
startup.processAssert(); | ||
startup.processConfig(); | ||
startup.processNextTick(); | ||
startup.processPromises(); | ||
startup.processStdio(); | ||
startup.processKillAndExit(); | ||
startup.processSignalHandlers(); | ||
|
@@ -264,8 +265,11 @@ | |
}); | ||
}; | ||
|
||
var addPendingUnhandledRejection; | ||
var hasBeenNotifiedProperty = new WeakMap(); | ||
startup.processNextTick = function() { | ||
var nextTickQueue = []; | ||
var pendingUnhandledRejections = []; | ||
var microtasksScheduled = false; | ||
|
||
// Used to run V8's micro task queue. | ||
|
@@ -318,7 +322,8 @@ | |
microtasksScheduled = false; | ||
_runMicrotasks(); | ||
|
||
if (tickInfo[kIndex] < tickInfo[kLength]) | ||
if (tickInfo[kIndex] < tickInfo[kLength] || | ||
emitPendingUnhandledRejections()) | ||
scheduleMicrotasks(); | ||
} | ||
|
||
|
@@ -388,6 +393,57 @@ | |
nextTickQueue.push(obj); | ||
tickInfo[kLength]++; | ||
} | ||
|
||
function emitPendingUnhandledRejections() { | ||
var hadListeners = false; | ||
while (pendingUnhandledRejections.length > 0) { | ||
var promise = pendingUnhandledRejections.shift(); | ||
var reason = pendingUnhandledRejections.shift(); | ||
if (hasBeenNotifiedProperty.get(promise) === false) { | ||
hasBeenNotifiedProperty.set(promise, true); | ||
if (!process.emit('unhandledRejection', reason, promise)) { | ||
// Nobody is listening. | ||
// TODO(petkaantonov) Take some default action, see #830 | ||
} else | ||
hadListeners = true; | ||
} | ||
} | ||
return hadListeners; | ||
} | ||
|
||
addPendingUnhandledRejection = function(promise, reason) { | ||
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. Why do it this way instead of just 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. The promiseSetup needs to access it as well |
||
pendingUnhandledRejections.push(promise, reason); | ||
scheduleMicrotasks(); | ||
}; | ||
}; | ||
|
||
startup.processPromises = function() { | ||
var promiseRejectEvent = process._promiseRejectEvent; | ||
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. Using an object is not wrong but I would just have created |
||
|
||
function unhandledRejection(promise, reason) { | ||
hasBeenNotifiedProperty.set(promise, false); | ||
addPendingUnhandledRejection(promise, reason); | ||
} | ||
|
||
function rejectionHandled(promise) { | ||
var hasBeenNotified = hasBeenNotifiedProperty.get(promise); | ||
if (hasBeenNotified !== undefined) { | ||
hasBeenNotifiedProperty.delete(promise); | ||
if (hasBeenNotified === true) | ||
process.emit('rejectionHandled', promise); | ||
} | ||
} | ||
|
||
process._setupPromises(function(event, promise, reason) { | ||
if (event === promiseRejectEvent.unhandled) | ||
unhandledRejection(promise, reason); | ||
else if (event === promiseRejectEvent.handled) | ||
process.nextTick(function() { | ||
rejectionHandled(promise); | ||
}); | ||
else | ||
NativeModule.require('assert').fail('unexpected PromiseRejectEvent'); | ||
}); | ||
}; | ||
|
||
function evalScript(name) { | ||
|
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.
Why not just directly emit "uncaughtException"? Is't it very similar?
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.
Rejections can be handled asynchronously after
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.
No, it is not. Choosing to deal with unhandled rejections like uncaught exceptions is a very opinionated choice.
I'm not saying I agree or disagree with it but it is a breaking change for many users regardless - and not one we should easily introduce. The current plan is to introduce these events now and then choose a default action later - one such default action is to throw the error for
"uncaughtException"
events to deal with it - there are people who like it and people who object to it. However, at first we need the very basic ability to deal with these events so this pull request makes the minimal changes required that don't make any breaking changes to existing io.js code.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.
Thanks, it is reasonable
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.
@golyshevd I've actually since opened an issue about this where you are welcome to argue your stance: #830