Please handle your Promises' errors
SlideShare - http://mact.me/7j
I'm going to demonstrate a problem with the way Promises and Domains interact in Node.js.
- A Promise is an object representing the eventual completion or failure of an asynchronous operation.
- A Domain is a way to route errors and uncaught exceptions across multiple asynchronous operations to a single context. This allows you handle the error or exception without losing the context.
Domains are deprecated. However, the replacement API has not been finalized. So if we want to take advantage of the features that Domains provide, we have no choice but to keep using them.
One popular web framework, Restify, has support for Domains built-in. Until very recently, this built-in support was inescapable. Although the latest versions of Restify v4 (v4.3.x) is allows you to opt-out, and as of v5, Domain support is actually opt-in, having no replacement for Domains means (in my opinion) that you should continue using Domains for the time being.
You're probably using Promises. And people have been having problems with Promises and Domains in Node.js for a long time.
Problem: unhandled Promise rejection will hang your web app.
UnhandledPromiseRejectionWarning
is not logged- server will hang
UnhandledPromiseRejectionWarning
is logged- server will hang
UnhandledPromiseRejectionWarning
is logged- additional
DeprecationWarning
is logged warning that in the future, Promise rejections that are not handled will terminate the Node.js process with a non-zero exit code - server will hang
Problem: Your app will still hang.
Confused?
Problem: We have succeeded in not swallowing errors, but we're still not handling all the rejections. See Part 1.
Progress, but...
Problem: We have lost the Domain (and therefore the request and response). So, we can crash, but we cannot respond with a 500 error.
Success!
But, why?!
Native Promises and bluebird Promises are implemented differently.
- Domains work as expected with bluebird Promises, which are userland code. But with native Promises, the active Domain has exited before the Promise rejection occurs.
- nodejs/node-v0.x-archive#8648 (comment)
But throw
?!
Restify's uncaughtException
handler will catch the exception because it handles Domain errors.
Explicitly use the Domain the rejected Promise is connected to.
Native Promises and bluebird Promises interact with Domains the same way.
http://thecodebarbarian.com/unhandled-promise-rejections-in-node.js.html