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 do not recognize execution contexts created when processing thenables #22360

Closed
medikoo opened this issue Aug 16, 2018 · 57 comments
Closed
Labels
async_hooks Issues and PRs related to the async hooks subsystem. feature request Issues that request new features to be added to Node.js.

Comments

@medikoo
Copy link

medikoo commented Aug 16, 2018

Promise.all to observe input promises, invokes promise.then in next event loop, at least it's what stack traces show in both Node.js and Google Chrome.

Still Async Hooks see it as same execution context, it can be seen by running following code:

const async_hooks = require('async_hooks');

async_hooks.createHook({ init() {} }).enable();

Promise.all([
  {
    then() {
      console.log(async_hooks.executionAsyncId(), async_hooks.triggerAsyncId(), 'thenable.then invoked by Promise.all');
      console.trace('thenable.then invoked by Promise.all');
    },
  },
]);

console.log(async_hooks.executionAsyncId(), async_hooks.triggerAsyncId(), 'Main');
console.trace('Main');

The outcome is:

1 0 'Main'
Trace: Main
    at Object.<anonymous> (/Users/medikoo/Projects/maas/maas-backend/test.js:15:9)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:266:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)
1 0 'promise.then invoked by Promise.all'
Trace: promise.then invoked by Promise.all
    at Object.then (/Users/medikoo/Projects/maas/maas-backend/test.js:9:15)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:266:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)

I've stumbled on that when trying to configure long stack trace solution for Node.js, and was dealing with custom promise implementations.

I believe that's not expected.

  • Version: v10.9.0 (observable also on v8)
  • Platform: macOs 10.13.6 (17G65)
@medikoo
Copy link
Author

medikoo commented Aug 16, 2018

As I see, it goes down to Promise.resolve:

const async_hooks = require('async_hooks');

async_hooks.createHook({ init() {} }).enable();

Promise.resolve({
  then() {
    console.log(
      async_hooks.executionAsyncId(),
      async_hooks.triggerAsyncId(),
      'thenable.then invoked by Promise.resolve'
    );
    console.trace('thenable.then invoked by Promise.resolve');
  },
});

console.log(async_hooks.executionAsyncId(), async_hooks.triggerAsyncId(), 'Main');
console.trace('Main');

Produces:

1 0 'Main'
Trace: Main
    at Object.<anonymous> (/Users/medikoo/Projects/maas/maas-backend/test.js:17:9)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:266:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)
1 0 'promise.then invoked by Promise.resolve'
Trace: promise.then invoked by Promise.resolve
    at Object.then (/Users/medikoo/Projects/maas/maas-backend/test.js:12:13)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:266:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)

@firedfox
Copy link
Contributor

  1. Installing async hooks via async_hooks.createHook enables promise execution tracking.
    As described here.

  2. Passing { then: Function } to Promise.all or Promise.resolve triggers then in current event loop because there is no Promise before then.

I think this is how to produce what you expected:

const async_hooks = require('async_hooks');

async_hooks.createHook({ init() {} }).enable();

console.log(async_hooks.executionAsyncId(), async_hooks.triggerAsyncId(), 'Main');
Promise.all([
  Promise.resolve().then(() => {
    console.log(async_hooks.executionAsyncId(), async_hooks.triggerAsyncId(), 'promise.then invoked by Promise.all');
    console.trace('promise.then invoked by Promise.all');
  }),
]);

Produces:

1 0 'Main'
7 6 'promise.then invoked by Promise.all'
Trace: promise.then invoked by Promise.all
    at Promise.all.Promise.resolve.then (/Users/firedfox/tmp/test.js:9:13)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:236:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:560:3)

@medikoo
Copy link
Author

medikoo commented Aug 16, 2018

@firedfox indeed I forgot about async_hooks.createHook({..}).enable() to make posted test case fully reliable. Still it was just mistake in code example (I've reedited it to avoid further confusion), adding that initialization doesn't help, outcome remains same.

Note: it's about an extra event loop in which then method is executed and not its callback. Your example tests the latter, that works without issues and it's not a concern here.

@medikoo
Copy link
Author

medikoo commented Aug 16, 2018

I've updated examples a bit more to better expose that we deal with different event loop, which is not reflected by async_hooks.executionAsyncId()

@firedfox
Copy link
Contributor

firedfox commented Aug 17, 2018

IMO, it's because { then: Function } you used is not a promise.then but just plain object.then.
The Promise.resolve() method returns a Promise object. So Promise.resolve().then gives us a promise.then. All other ways that return a Promise object should produce the same result.

Sorry I finally understand what you mean. You are right. It seems to be a problem.

const async_hooks = require('async_hooks');

async_hooks.createHook({ init() {} }).enable();

Promise.all([
  {
    then() {
      console.log(async_hooks.executionAsyncId(), async_hooks.triggerAsyncId(), 'promise.then invoked by Promise.all');
      console.trace('promise.then invoked by Promise.all');
    },
  },
]);

process.nextTick(() => {
  console.log(async_hooks.executionAsyncId(), async_hooks.triggerAsyncId(), 'nextTick');
  console.trace('nextTick');
});

console.log(async_hooks.executionAsyncId(), async_hooks.triggerAsyncId(), 'Main');

Produces:

1 0 'Main'
Trace: Main
    at Object.<anonymous> (/Users/firedfox/tmp/test.js:20:9)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:236:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:560:3)
8 1 'nextTick'
Trace: nextTick
    at process.nextTick (/Users/firedfox/tmp/test.js:16:11)
    at process._tickCallback (internal/process/next_tick.js:61:11)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:236:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:560:3)
1 0 'promise.then invoked by Promise.all'
Trace: promise.then invoked by Promise.all
    at Object.then (/Users/firedfox/tmp/test.js:9:15)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
    at startup (internal/bootstrap/node.js:236:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:560:3)

@medikoo
Copy link
Author

medikoo commented Aug 17, 2018

@firedfox I don't understand how your comment is relevant to this report?

Again, bug is that async contexts in which thenable.then is called by any native Promise method is not exposed by async_hooks as expected.

This bug makes async_hooks unreliable for cases when we work with custom thenables, and that's not that uncommon, e.g. you can find them in quite popular knex library.
With current state of things, it's not possible to get information about trigger async context, within scope of that then method invocation (when invoked by native Promise method)

As long as it's the case, reliable long stack trace solution cannot be configured using async_hooks.

@jasnell
Copy link
Member

jasnell commented Aug 17, 2018

I believe the issue here is more about the fact that async_hooks does not currently track thenables in the same way that it tracks actual Promise instances. Because the thenable here is not actually visible to async_hooks, it is not able to do the appropriate context association.

@medikoo
Copy link
Author

medikoo commented Aug 17, 2018

Because the thenable here is not actually visible to async_hooks, it is not able to do the appropriate context association.

I'm not sure if it's a valid explanation, as here it's native Promise.all that's responsible for introduction of new async context, and not thenable that's passed to it.

I suppose that if async_hooks can monitor moments in which callbacks passed to promise.then are invoked (by promise.then internals), same way it should be able to monitor invocations of thenable.then (which are made within Promise.resolve internals)

I take that code responsible for that is in C++ layer (?)

@jasnell
Copy link
Member

jasnell commented Aug 17, 2018

The state of Promise resolution is tracked using an API at the C++ layer. Thenables do not tap into that mechanism and therefore cannot be tracked the same way as normal promises.

You can visualize the difference using the clinic bubbleprof tool

thenable:

Promise.all([
  {
    then() {
      console.log('a')
    }
  }
])

https://upload.clinicjs.org/public/7c8bcbc1db0fdaf015a34941a1fbfa0b32db378f8d6b5b06db9031df7cd48f76/171215.clinic-bubbleprof.html

promise:

Promise.all([
  Promise.resolve('a').then(console.log)
])

https://upload.clinicjs.org/public/8a263182a3c9a50c2d4066aa22eae417cb5c6366e9977e2fef6560d7ff6f87e7/171277.clinic-bubbleprof.html

If you explore the differences between the two call graphs, you'll see that the thenable is not seen by V8 or Node.js as a promise and therefore cannot be tracked in the same way.

@medikoo
Copy link
Author

medikoo commented Aug 17, 2018

I don't see those two examples equivalent. In first one console.log is within a body of then, and in second one it makes a body of a callback passed to then, and that's a quite big difference.
Technically first example involves two event loops, and second three event loops.

Anyway to make sure I understand you right - you acknowledge there's an event loop introduced by native Promise internals (so V8) to resolve thenables, but want to point that it's not exposed properly outside, so cannot picked by async_hooks, and therefore it's not possible to fix this issue?

@devsnek
Copy link
Member

devsnek commented Aug 17, 2018

async_hooks tracks promises, not the event loop's promise job queue.

@medikoo
Copy link
Author

medikoo commented Aug 17, 2018

async_hooks tracks promises, not the event loop's promise job queue.

Ok, clear, so event loops tracking is made purely by following promise instances, which in turn makes it not perfectly complete (as not all enqueued jobs within V8 are mapped to new async contexts).

Question is whether this should be considered a feature or a bug? :)

@stephenh
Copy link

@medikoo I'm just wandering by, but does this comment in the google stackdriver tracer address/work around your observation?

https://github.com/GoogleCloudPlatform/cloud-trace-nodejs/blob/master/src/cls/async-hooks.ts#L62

@medikoo
Copy link
Author

medikoo commented Aug 29, 2018

@stephenh it doesn't look related to this issue. PROMISE type reflects promise initialization, and here issue is that we miss tracking of execution contexts created by V8 for processing thenables (those do not involve promise creation).

@Trott
Copy link
Member

Trott commented Nov 16, 2018

Question is whether this should be considered a feature or a bug? :)

@nodejs/async_hooks Thoughts? This is a bug that should be fixed and/or a feature that needs to be implemented? Or this is working as intended and can be closed?

@AndreasMadsen
Copy link
Member

As I recall, the executeAsuncId should be 0 to indicate a missing context. That is the only bug here.

If a user implements thenables or anything else that can't be tracked, they need to use a AsyncResource instance to maintain the context. The same is the case for bluebird promises, as an example.

@medikoo medikoo changed the title Async Hooks do not recognize execution contexts as created by Promise.all Async Hooks do not recognize execution contexts created when processing thenables Nov 17, 2018
@medikoo
Copy link
Author

medikoo commented Nov 19, 2018

Thanks @AndreasMadsen I just checked and indeed that can be workaround with AsyncResource, so that's a good news!

While thenable.then is invoked in next tick, it is actually retrieved immediatelly from thenable, on basis of that we can configure well working async resource by defining a then as a getter.

Working proof of a concept:

const { createHook, executionAsyncId, triggerAsyncId, AsyncResource } = require("async_hooks");

const events = [];
process.on("exit", () => {
  console.log(events);
});

createHook({
  init(asyncId, type, triggerAsyncId) {
    events.push(["init", asyncId, type, triggerAsyncId]);
  },
  before(asyncId) {
    events.push(["before", asyncId]);
  },
  after(asyncId) {
    events.push(["after", asyncId]);
  }
}).enable();

class Thenable {
  get then() {
    const asyncResource = new AsyncResource("Thenable");
    console.trace(executionAsyncId(), triggerAsyncId(), "get thenable.then");
    return function(onSuccess, onFailure) {
      return asyncResource.runInAsyncScope(
        (onSuccess, onFailure) => {
          console.trace(executionAsyncId(), triggerAsyncId(), "thenable.then");
        },
        this,
        onSuccess,
        onFailure
      );
    };
  }
}

const thenable = new Thenable();

const outerNotAccessibleContext = thenable =>
  setTimeout(() => {
    console.trace(executionAsyncId(), triggerAsyncId(), "setTimeout");
    Promise.resolve(thenable);
  });

outerNotAccessibleContext(new Thenable());

console.trace(executionAsyncId(), triggerAsyncId(), "Main");

As I take it's how it's supposed to work, I'm closing the issue

@medikoo medikoo closed this as completed Nov 19, 2018
@medikoo
Copy link
Author

medikoo commented Nov 19, 2018

The only subtle issue is that, such new async resource should be created only in case then is retrieved by V8 async queue logic, and there are no straightforward means to detect that.
Best we can do probably is to examine current stack trace.

@AndreasMadsen
Copy link
Member

Alternativly, just make Thenable inherit from AsyncResource. What you prefer, depends on how you want the async context to flow.

@medikoo
Copy link
Author

medikoo commented Nov 20, 2018

Alternativly, just make Thenable inherit from AsyncResource

As far as I understand it that won't work, as we need AsyncResource instance not per thenable but per one thenable.then invocation (and per one thenable there can be many invocations in different async contexts)

Generally current means do not leave us with any solid solution for that problem. As even if we hack in as a then getter, we don't know whether it's a V8 async queue that retrieves then (and it's only in that case when new AsyncResource should be initialized, otherwise we expose weird side effects that may expose misinformation about async contexts)

@AndreasMadsen
Copy link
Member

AndreasMadsen commented Nov 20, 2018

As far as I understand it that won't work, as we need AsyncResource instance not per thenable but per one thenable.then invocation (and per one thenable there can be many invocations in different async contexts)

Not really correct. In the AsyncHooks model, the promise is the AsyncResource.

Consider this logger:

const { createHook } = require('async_hooks')

const asyncHook = createHook({
  init (asyncId, type, triggerAsyncId, resource) {
    process._rawDebug('init', asyncId, type);
  },

  before (asyncId) {
    process._rawDebug('before', asyncId);
  },

  after (asyncId) {
    process._rawDebug('after', asyncId);
  },

  destroy (asyncId) {
    process._rawDebug('destroy', asyncId);
  },

  promiseResolve (asyncId) {
    process._rawDebug('resolve', asyncId);
  }
})
asyncHook.enable()

Then consider this code:

const thenable = new Promise(function (resolve) {
  resolve(1);
});

That emits:

init 5 PROMISE
resolve 5

so I would try:

class ImmediateThenable extends AsyncResource {
  constructor(value) {
    super('ImmediateThenable');
    this._value = value;
  }

  then(onSuccess, onFailure) {
    return this.runInAsyncScope(function (onSuccess, onFailure) {
      if (onSuccess) onSuccess(this._value);
    }, this, onSuccess, onFailure);
  }
}

@medikoo
Copy link
Author

medikoo commented Nov 20, 2018

Use case I'm addressing is connecting async stack contexts to produce reliable long stack traces.

As far as I understand with async_hooks I can achieve it by gathering stack trace at init event, and appending it to any stack generated betwen before and after events for given async resource.

So e.g. in following example result should be that console.trace at A3 should expose stack that joins traces from A1, A2 and A3 points, same way B3 should join stacks fro B1, B2 and B3 points.
(note that while A1 and B1 point same async contexts, it's not the same with A2 and B2, and A3 and B3).

const { createHook, executionAsyncId, triggerAsyncId, AsyncResource } = require("async_hooks");

const getStack = () =>
  new Error().stack
    .split("\n")
    .slice(2)
    .join("\n");

const asyncHook = createHook({
  init(asyncId, type, triggerAsyncId, resource) {
    process._rawDebug("init", asyncId, type, getStack());
  },
  before(asyncId) {
    process._rawDebug("before", asyncId);
  },
  after(asyncId) {
    process._rawDebug("after", asyncId);
  },
  destroy(asyncId) {
    process._rawDebug("destroy", asyncId);
  },
  promiseResolve(asyncId) {
    process._rawDebug("resolve", asyncId);
  }
});
asyncHook.enable();

class Thenable extends AsyncResource {
  constructor(value) {
    super("Thenable");
  }

  then(onSuccess, onFailure) {
    return this.runInAsyncScope(
      function(onSuccess, onFailure) {
        // Invoked twice in different async contexts
        process._rawDebug("A3 or B3", getStack());
      },
      this,
      onSuccess,
      onFailure
    );
  }
}

const thenable = new Thenable();

process._rawDebug("A1", getStack());
setTimeout(() => {
  process._rawDebug("A2", getStack());
  Promise.resolve(thenable);
}, 100);

process._rawDebug("B1", getStack());
setTimeout(() => {
  process._rawDebug("B2", getStack());
  Promise.resolve(thenable);
}, 50);

Now if you examine log output. There are two issues:

  • Two different async contexts created by two distinctthenable.then resolutions are presented with same id (5). It doesn't appear as right to me.
  • We lack information on where each thenable.then async context really initializes. Technically it should point to context in which Promise.resolve call was made. By looking into logs we see that PROMISE type resources point there (as new promises are created by Promise.resolve), but that information is disconnected from thenables. I don't have means to correctly map it to thenable.then resolutions.

@AndreasMadsen
Copy link
Member

As far as I understand with async_hooks I can achieve it by gathering stack trace at init event, and appending it to any stack generated betwen before and after events for given async resource.

Not necessarily. This is the general rule I would use but for promises, it can get very complicated. Because there multiple places in your code that you may consider the "start".

  • new Promise(): this would be the init event like you suggest.
  • resolve(value): instead of init you should use the promiseResolve event.
  • .then(): calling .then() creates a new promise. Instead of the init event of the parent promise, use the init of this "chainedPromise".

When you are arguing your point, please be aware that all these 3 different places of "origin" are valid. There is no true origin for a promise, which is why we need to allow all three types.

@medikoo
Copy link
Author

medikoo commented Nov 21, 2018

In case I'm after init event emitted at new Promise() is irrelevant, as this doesn't technically produce any new async context my code would be run in (I don't loose any stack continuity here)

It's at promise.then() or resolve(value) when this happens. So I want to bridge in stack a point of where promise.then() was invoked with point where callback passed to then was invoked, and similarly, point of where resolve(thenable) was invoked with point where thenable.then was invoked.

So while promiseResolve event is invoked on resolve(thenable), there's still no straightforward way to connect this with given thenable.then invocation. The solution I see, is to:

  • gather stack trace at promiseResolve
  • if thenable.then is retrieved after promiseResolve event, both happened in same async context, and share same stack trace. Then we can I assume it's resolve(thenable) operation, and initialize new async resource.

@AndreasMadsen
Copy link
Member

Sorry, I don't get what the issue is. I think my "point 3" is what you need. Apparently, you say it isn't. As far as I can see every single point of execution regarding promises is somehow exposed. So I really don't get it.

/cc @jasnell @nodejs/async_hooks – I don't get this, maybe one of you can help.

@medikoo
Copy link
Author

medikoo commented Nov 21, 2018

Sorry, I don't get what the issue is.

Putting it is as simple as possible:

With help of async hooks, I want to construct a long stack trace solution that will produce an expected stack trace in below example:

class Thenable {
  then() {
    // Stack trace that expose that this originated at `Promise.resolve(thenable)`
    console.trace();
  }
}
Promise.resolve(new Thenable());

I don't see a straightforward way to achieve it (best I came up with is configuring thenable.then as a getter and put some monitoring logic there)

@AndreasMadsen
Copy link
Member

I don't think this has anything to do with it being a Thenable and not a promise. If you are implementing your own Thenable, then you need to create an AsyncRessource instance to maintain context!

In this case, use the init event.

If what you really mean is that you want

class Thenable {
  then() {
    // Stack trace that expose that this originated at `Promise.resolve(thenable)`
    console.trace();
  }
}
const thenable = new Thenable();
Promise.resolve(thenable);

to show Promise.resolve(thenable); in the stack trace. Then then() should create another Thenable (just like an ordinary Promise would do), then use the init event for that promise.

@medikoo
Copy link
Author

medikoo commented Nov 23, 2018

I'll try to clarify it further:

  • To rely on async_hook to connect stack traces, the init event for given new context should be emitted in parent (trigger) async context and not in same one in which before and after are emitted.
  • I'm addressing use case of lazy thenables, so one where in context of then invocation there's some significant work going on (it's not internals we want to hide as it's the case with native promises) and eventual crash (or console.trace) in there should produce expected stack trace.

So situation is as follows:

class Thenable {
  then() {
    // ('before' event should be emitted at this point)
    // As we're already in new executed async context
    // (invoked in other microtask by V8 async queue) 
    // it's too late here for 'init' event and if one was not emitted at trigger context
    // we lost means to connect stack trace with `Promise.resolve(thenable)`
    const returnValue = new Thenable(); // 'init' event here brings no valuable info
    // .. lazy thenable.then operations
    console.trace(); // Let me see Promise.resolve(thenable) here
    // ... lazy thenable.then operation
    return returnValue;
    // ('after' event should be emitted at this point)
  }
}
const thenable = new Thenable(); // 'init' event here brings no valuable info, see below:
// Added setTimeout to show that resolution of thenable.then may happen
// at very different context than thenable construction
setTimeout(() => {
  // Below line triggers new async context
  Promise.resolve(thenable); // ('init' event should be emitted at this point)
});

So from what I see, following suggestion:

then() should create another Thenable (just like an ordinary Promise would do), then use the init event for that promise.

Won't work for this use case.

@Qard
Copy link
Member

Qard commented Aug 13, 2019

@sam-github It's possible. Someone just needs to put the time into it.

I already discussed it with some V8 folks a few months ago and the conclusion seemed to be that a change for that would be fine, but it's not a priority for them to work on it. I had hoped to find some time to dig into it myself, but I haven't got to it yet. 😞

@Flarna
Copy link
Member

Flarna commented Aug 13, 2019

I'm quite sure that a lot problems seen now (e.g. when "starts" a promise based transaction, support from libraries using connection pooling,...) would get solved or at least less problematic on the long run once await is fully supported by AsyncHooks.
I have the impression that more and more libraries/applications move from callback/pure Promise style to await and this allows to get the logical application flow automatically - as a result less need to move this responsibility into libraries.
At least this is the impression after discussion with colleagues working with .NET where await is used heavily since a while (and AsyncLocal is there too support CLS) and as far as I know they never had callback/Promise style Apis like Node.

As @Qard said it's "just" a matter of doing the work - but this is not an easy task for a v8 newbie. Not even sure if it is easy for v8 experts to get this functional correct and efficient.

@AndreasMadsen
Copy link
Member

has delimited the problem space pretty clearly around promises, so I'll re-include his description here

@othiym23 Having thought about this for some years now. I'm now convinced that .then() is the correct choice for async_hooks and that other starting points should be exposed through a promise_hooks module without adding complexity to async_hooks. Unfortunately, that is not how it is currently done.

@gireeshpunathil
Copy link
Member

gireeshpunathil commented Oct 23, 2019

In the diagnostic working group meeting today, we discussed and decided to remove this from the regular agenda (folks who originally brought this up not available to make progress)

@Flarna
Copy link
Member

Flarna commented Oct 24, 2019

Is hacking await from v8 out of the question?

I think this is the only path forward here.
I never hacked v8... is there a "get started with v8" somewhere to reduce the boarding hurdle and get faster to the actual location in V8 where to hack?

@Flarna
Copy link
Member

Flarna commented Jul 2, 2020

I think this is fixed via #33778 (included in 14.5.0).

@Qard
Copy link
Member

Qard commented Jul 2, 2020

Yep.

@Qard Qard closed this as completed Jul 2, 2020
@medikoo
Copy link
Author

medikoo commented Jul 3, 2020

Wow @Qard, thank you!

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. feature request Issues that request new features to be added to Node.js.
Projects
None yet
Development

No branches or pull requests