Skip to content

async-wrap: no way to catch errors without changing the throw origin #669

Closed
@AndreasMadsen

Description

Consider some long stack trace module. It can use async_wrap to manage the the callSite objects correctly and use the v8 Error hooks to modify the .stack property. However because v8 sets the .stack property in a lazy way, it is necessary to do a try {} finally {} around the callback.

See https://github.com/AndreasMadsen/trace/blob/master/trace.js#L53 for an example with the tracing module.

An okay solution solution is to use the uncaughtException event like this:

var asyncWrap = process.binding('async_wrap');

// Enable asyncWrap and call init hook function on async initialization
var asyncHooksObject = {};
var kCallInitHook = 0;
asyncWrap.setupHooks(
  asyncHooksObject,
  asyncFunctionInitialized,
  asyncCallbackBefore,
  asyncCallbackAfter);
asyncHooksObject[kCallInitHook] = 1;

function asyncFunctionInitialized() {}

function asyncCallbackBefore() {
  process.once('uncaughtException', asyncCallbackError);
}

function asyncCallbackError(error) {
  // Set stack by v8 magic
  error.stack;

  // changes throw origin, should not be necessary
  throw error;
}

function asyncCallbackAfter() {
  process.removeListener('uncaughtException', asyncCallbackError);
}

setTimeout(function () {
  badluck();
}, 10);

However this changes the throw origin:

/Users/Andreas/Sites/node_modules/trace/test.js:26
  throw error;
        ^
ReferenceError: badluck is not defined
    at null._onTimeout (/Users/Andreas/Sites/node_modules/trace/test.js:34:3)
    at Timer.listOnTimeout (timers.js:90:15)

If uncaughtException isn't used then this is the error:

/Users/Andreas/Sites/node_modules/trace/test.js:34
  badluck();
  ^
ReferenceError: badluck is not defined
    at null._onTimeout (/Users/Andreas/Sites/node_modules/trace/test.js:34:3)
    at Timer.listOnTimeout (timers.js:90:15)

This is much more informative. It would be really nice if async_wrap or some other mechanism allowed something similar to the old tracing.addAsyncListener({ error: handler }) behaviour. Such that the throw origin can be preserved.

issue tracking: AndreasMadsen/trace#12
issue tracking: nodejs/diagnostics#7

Metadata

Assignees

Labels

feature requestIssues that request new features to be added to Node.js.stalledIssues and PRs that are stalled.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions