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

πŸ› Bug Report β€” Runtime APIs: The AsyncContext of AsynLocalStorages gets lost in custom thenables #1513

Closed
dario-piotrowicz opened this issue Dec 29, 2023 · 19 comments
Assignees
Labels
bug Something isn't working nodejs compat v8

Comments

@dario-piotrowicz
Copy link
Member

If I define a custom thenable and try to access the store of an AsyncLocalStorage in the then method, the store seems to be undefined although it shouldn't be.

Basically:

import { AsyncLocalStorage } from 'node:async_hooks';

const als = new AsyncLocalStorage();

export default {
  async fetch() {
    return als.run({ }, async () => {
      const thenable = {
        then(onfulfilled) {
          // ...
          als.getStore(); // <- yields undefined ❌
        },
      };
       // ...
    });
  },
};

minimal reproduction

@jasnell
Copy link
Member

jasnell commented Jan 2, 2024

Ah, yes, custom thenables do not currently automatically propagate the async context. You'll need to use AsyncLocalContext.bind(...) or AsyncLocalContext.snapshot(...) with the thenable to capture the context.

const thenable = {
  then: AsyncLocalStorage.bind(function (onfulfilled) {
    als.getStore();
  })
};

@dario-piotrowicz
Copy link
Member Author

dario-piotrowicz commented Jan 2, 2024

@jasnell I see but I assume that this can be improved/fixed? is propagating the async context for thenables something potentially problematic/complex?

As you can see in cloudflare/next-on-pages#499 the problem is that libraries can use thenables so application authors could be unable use the bind/snapshot workaround πŸ₯²

@jasnell
Copy link
Member

jasnell commented Jan 2, 2024

It requires a fix in v8 to get working. We can patch v8 to get it working but I've been waiting on a larger change coming for the implementation of the standardized AsyncContext API. I was hoping that would come faster than it has but it's looking like there's no ETA yet. I can work up the patch and we can float it until v8 receives the other updates.

@dario-piotrowicz
Copy link
Member Author

@jasnell yeah that would be awesome since I have seen a few developers hitting this issue πŸ˜„

Hopefully it's not too too much work/complex to implement such temporary patch? 🀞

@jasnell jasnell added bug Something isn't working v8 nodejs compat labels Jan 3, 2024
@paramaggarwal
Copy link

Any suggested workaround meanwhile? I am unable to use Prisma on CloudflareWorkers currently.

@jasnell
Copy link
Member

jasnell commented Feb 4, 2024

The immediate workaround is to use AsyncLocalStorage.snapshot(...) ...

For example... (this doesn't use a thenable but the idea should be clear)...

class Foo {
  #runInAsyncScope = AsyncLocalStorage.snapshot();

  get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
}

Essentially, your custom thenable would use AsyncLocalStorage.snapshot() to capture the relevant context and enter it manually when the thenable is invoked.

@dario-piotrowicz
Copy link
Member Author

@jasnell I assume that the V8 change hasn't landed yet? πŸ˜“

Regarding the workaround, as I mentioned here: cloudflare/next-on-pages#499 (comment) I think that unfortunately the workaround is a bit impractical when thenables come from libraries.

Since people keep hitting this issue I would be curious to know if there's an ETA for the V8 change, alternatively as I mentioned in my next-on-pages comment maybe we could there do some hacks and try to patch all thenables present in the code, but before we consider doing that I'd be curious about the effort required in workerd to patch this and the brittleness of the solution since, as I mentioned, a next-on-pages hack would be:

  • brittle
  • complex
  • costly (it would likely significantly increase build time)
  • fix this problem only for apps using next-on-pages

So I'm wondering, if we want to fix this, where it would make more sense to do so (I'm definitely leaning towards workerd but as I mentioned I don't really know what the fix there implies)

@jasnell
Copy link
Member

jasnell commented Feb 6, 2024

... where it would make more sense to do so

No ETA yet on the v8 change. I'll look at it today. The change definitely needs to be made in v8. We don't have the necessary visibility in to the necessary bits within v8 to apply a reasonable workaround in workerd.

@jasnell jasnell self-assigned this Feb 8, 2024
@jasnell
Copy link
Member

jasnell commented Feb 8, 2024

... The change definitely needs to be made in v8...

To clarify, when I say this, I mean that the limitation here is within v8 itself and to fix it requires a patch to v8. We can float a patch that addresses this but ultimately, long term, it's something that v8 needs to address. My plan currently is to float a patch and I have one in testing internally. Assuming that looks good I'll be able to open a PR here.

@paramaggarwal
Copy link

Oh I see. Thanks for looking so deeply into this. Do you think there is long-term merit in using JavascriptCore instead of V8? It would reduce resource utilisation on Cloudflare Edge Network right?

@jasnell
Copy link
Member

jasnell commented Feb 8, 2024

... long-term merit in using JavascriptCore instead of V8 ...

Not necessarily. While we've always had a Side Quest in mind of making workers somewhat agnostic of the js runtime the reality is that v8 is a hard dependency. It's not clear at all that switching to something like JSC would yield enough of a realized benefit to justify the development effort it would take. This issue around the async context propagation, on its own, certainly would not be enough justification.

@jasnell
Copy link
Member

jasnell commented Feb 9, 2024

Quick update... I've got the v8 patch put together and internal testing is showing that it's good. I want to get some review before I open the PR that adds the patch here. But, progress!

@Qard ... just a heads up that I was able to use your older patch as a roadmap here. When I open the PR here, the patch should contain everything you need to move forward to upstream the updated patch in v8 itself.

@Qard
Copy link

Qard commented Feb 9, 2024

Nice! That was quick work. πŸŽ‰

@rakibatomnixima
Copy link

waiting for the patch, thanks for your hard work!

@jellohouse
Copy link

Waiting for the patch as well - Hope it gets fixed soon!
Is there an ETA?

@kentonv
Copy link
Member

kentonv commented Feb 20, 2024

Fixed by #1665 which was merged yesterday. Likely will go to production some time next week.

@jasnell
Copy link
Member

jasnell commented Feb 22, 2024

Going to go ahead and close this issue now since the fix has landed. As Kenton mentioned, if all goes well that'll end up in production likely by next week.

@jasnell jasnell closed this as completed Feb 22, 2024
@janpio
Copy link

janpio commented Feb 22, 2024

We @prisma would appreciate a further comment here when this has been rolled out to production, so we can confirm and then remove documentation for the current blocking problem. Thanks.

@kentonv
Copy link
Member

kentonv commented Feb 24, 2024

This is now in production.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working nodejs compat v8
Projects
None yet
Development

No branches or pull requests

8 participants