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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions