Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async_hooks: Awaited thenables have no async context after first tick #26064

Closed
kjin opened this issue Feb 13, 2019 · 3 comments
Closed

async_hooks: Awaited thenables have no async context after first tick #26064

kjin opened this issue Feb 13, 2019 · 3 comments
Labels
async_hooks Issues and PRs related to the async hooks subsystem.

Comments

@kjin
Copy link
Contributor

kjin commented Feb 13, 2019

  • Version: 11.9, 10.15
  • Platform: macOS
  • Subsystem: async_hooks

If I do await { then: fn }, then code running in fn will always see an async ID of 1 until after an Immediate (or "lower priority" tick) is made, then it will start seeing 0 instead. I expect it instead to be the same async ID as the resource in which the call was made... see the below repro for expectations vs. actual results.

The culprit here is probably the same as in #22360, but discussion there has stalled. Also, I think the example here is easier to comprehend.

Repro

const asyncHooks = require('async_hooks');

// activate async_hooks
asyncHooks.createHook({
  init: () => {}
}).enable();

// a custom thenable
const thenable = () => ({
  then: (fn) => {
    console.log(asyncHooks.executionAsyncId());
    fn();
  }
});

async function main() {
  // On first tick
  console.log(asyncHooks.executionAsyncId()); // prints 1
  await thenable(); // prints 1 (expected)

  // After first thenable
  console.log(asyncHooks.executionAsyncId()); // prints incremented ID
  await thenable(); // still prints 1 (unexpected)

  // After high-priority tick
  await new Promise(res => process.nextTick(res)); // tick nextTick queue
  console.log(asyncHooks.executionAsyncId()); // prints incremented ID
  await thenable(); // still prints 1 (unexpected)

  // After Immediate
  await new Promise(res => setImmediate(res)); // tick immediate
  console.log(asyncHooks.executionAsyncId()); // prints incremented ID
  await thenable(); // prints 0 (unexpected)

  // A workaround
  console.log(asyncHooks.executionAsyncId()); // prints incremented ID
  await thenable().then(_ => _); // prints same as above (expected)
}

main().catch(console.error);

Real-world use case example

The knex module seems to sometimes make DB queries in a Promise.prototype.then wrapper. If the Promise implementation happens to be userland, like in bluebird, then async context will be unknown at the DB query call site.

@devsnek
Copy link
Member

devsnek commented Feb 13, 2019

if you want to track bluebird promises, bluebird needs to be async_hooks aware, or you need to patch async_hooks behaviour into it. async_hooks can't track what it doesn't know.

@kjin
Copy link
Contributor Author

kjin commented Feb 13, 2019

@devsnek I'm aware that bluebird doesn't currently have async_hooks interop, I believe it's an orthogonal issue. The bug here isn't whether the correct async ID is present in code running in the then callback, it's whether the correct async ID is present in the implementation of then itself.

@Trott Trott added the async_hooks Issues and PRs related to the async hooks subsystem. label Feb 13, 2019
@kjin kjin changed the title Awaited thenables have no async context after first tick async_hooks: Awaited thenables have no async context after first tick May 6, 2019
@devsnek
Copy link
Member

devsnek commented May 7, 2019

Duplicate of #22360

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
async_hooks Issues and PRs related to the async hooks subsystem.
Projects
None yet
Development

No branches or pull requests

3 participants