Skip to content

async_hooks: promise callbacks have no context unless init hook presentΒ #18520

@ofrobots

Description

@ofrobots

While going through some examples I ran into the following buggy behavior in async_hooks. Promise callbacks don't seem to have context by default. Even more surprisingly Adding a dummy init makes the context appears as if by magic!

I intend to look at this in detail later, but opening the issue now in case someone else wants to take a peek.

const ah = require('async_hooks');

let hooks;
switch (process.argv[2]) {
  default:
  console.log('run this test with a numeric argument');
  process.exit(1);

  case '1':
    hooks = {}; // no hooks
    break;

  case '2':
    hooks = { init() {} }; // empty init hook
    break;
}

ah.createHook(hooks).enable();
Promise.resolve(1729).then(() => {
  console.log(`then callback ran with eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
});

Unlike timers, and other Node.js async APIs (e.g. fs.read), by default the triggerAsyncId is always 0 (i.e. missing context) inside the then callback. The behaviour is the same when no hooks are present or an empty set of hooks are present.

❯ node p2.js 1
then callback ran with eid 1 tid 0

Attaching an empty init hook magically makes the context appear:

❯ node p2.js 2
then callback ran with eid 7 tid 6

Replacing the promise example with a setTimeout or fs.readFile has the things working correctly in all scenarios.

// the rest of the code is the same
setTimeout(() => {
  console.log(`timeout callback ran with eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
}, 1);
~/tmp/ah
❯ node p2.js 1
timeout callback ran with eid 6 tid 1

~/tmp/ah
❯ node p2.js 2
timeout callback ran with eid 6 tid 1

Metadata

Metadata

Assignees

No one assigned

    Labels

    async_hooksIssues and PRs related to the async hooks subsystem.promisesIssues and PRs related to ECMAScript promises.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions