Skip to content

Instantly share code, notes, and snippets.

@benjamingr
Last active October 6, 2023 08:31
Show Gist options
  • Star 69 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save benjamingr/0237932cee84712951a2 to your computer and use it in GitHub Desktop.
Save benjamingr/0237932cee84712951a2 to your computer and use it in GitHub Desktop.
Promise unhandled rejection tracking global handler hook

Possibly Unhandled Rejection NodeJS Promise Hook

###Unhandled Rejection Tracking

Several promise libraries such as bluebird and when as well as some native promise implementations offer potentially unhandled rejection tracking. This means that the following:

Promise.reject(new Error("err")); // never attach a `catch`

Does not get silently suppressed being an error but instead gets logged to the console or otherwise treated by the promise library. A common request is a way to handle rejection application wide. NodeJS code often includes several copies of the same promise library or different promise libraries and it is currently difficult to install a global hook on potentially unhandled rejections. For example code using Bluebird for concurrency, akamai for their API, bookshelf as an ORM and request-promise for web requests uses 4 promise libraries already - 3 Bluebirds and a WhenJS. If someone wants to log errors for all tracked unhandled rejections they'd have to add at least four handlers - if they miss any their code won't do what they expect.

This document attempts to offer a standard way for promise libraries and potentially native promises in Node to communicate they have detected an unhandled rejection.

##The hook

In order to handle rejections the following new events will be fired on process:

###Event 'unhandledRejection':

Emitted whenever a possibly unhandled rejection is detected. This event is emitted with the following arguments:

  • reason the rejection reason of the promise susprected in having an unhandled rejection
  • p the promise suspected in having an unhandled rejection itself.
process.on('unhandledRejection', function(reason, p){
    console.log("Possibly Unhandled Rejection at: Promise ", p, " reason: ", reason);
    // application specific logging here
});

###Event 'rejectionHandled':

Emitted whenever a possibly unhandled rejection was mistakenly identified and was eventually handled. For example if the promise library made a mistake considering p in the following case unhandled:

let p = Promise.reject(new Error("err"));

setTimeout(() => p.catch(function(){}), 86400);

This event is emitted with the following arguments:

  • p the promise who was believed to be an unhandled rejection.

This event is useful in order to recover from detection mistakes. While in my experience this rarely happens in practice this additional hook helps in such cases.

##Backwards incompatible changes

None that I am aware of. No one is currently firing events by these names in NodeJS code in GitHub.

##In other languages

Promises as an abstraction are indeed not unique to JavaScript - let's explore what other languages do.

So overall it seems like other programming environments support a unhandled rejection hander. Note that JavaScript is pretty special in that it is the only case I know of where a lot of different implementations of this abstract concept exist.

##Statistics

These are usage statistics about events current libraries already fire. These usage examples were collected from public GitHub projects using bluebird promises offering (non-global) hooks.

First a summary of bluebird's onPossiblyUnhandledRejection from GitHub. Large (>1000 stars) libraries typically don't change onPossiblyUnhandledRejection, the largest ORMS: Sequelize, Waterline and Bookshelf do not hook on it however users of those libraries sometimes do. It also very common for people to override it in test code.

Here are libraries and projects using onPossiblyUnhandledRejection in their code:

##Future work

Add a similar solution for promise libraries in browsers, possibly the WhatWG proposal.

##Related work:

@benjamingr
Copy link
Author

If you don't have any logic to run in the case of an exception - that's a bug and your server should probably crash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment