-
Notifications
You must be signed in to change notification settings - Fork 29.6k
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
Promise hooks don't work well in vm contexts #38781
Comments
/cc @Qard |
It's because it creates new Consider this: const vm = require('vm')
const context = vm.createContext({
require,
console
})
vm.runInContext(`
const ah = require('async_hooks')
ah.createHook({
init (asyncId, type, triggerAsyncId, resource) {
if (type === 'PROMISE') {
console.log('I stole a promise from outside my context!', resource)
}
}
}).enable()
`, context)
Promise.resolve() The intent is to make the rest of async_hooks context-scoped too so resources can't leak into other contexts. Depending on how you look at it, this change either breaks compatibility or is a partial bug fix. Either way, async_hooks is experimental, so breaking compatibility for the sake of correctness should be acceptable, as far as I understand. I've discussed the context-scoping concerns with a few other Node.js core folks in the past and the thinking from them seemed to be in agreement with me that isolate-scoping was wrong and that it would be a bug fix to context-scope it. I would understand if we chose to hold off on the context-based PromiseHook API until the rest of async_hooks is also adapted to be context-scoped, however that's a large change in itself which I likely won't have the bandwidth to work on in the near future. |
There is not intent for the user to jump between contexts. See the following: const vm = require('vm');
const { AsyncLocalStorage } = require('async_hooks')
const context = vm.createContext({
AsyncLocalStorage,
console,
});
vm.runInContext(`
const storage = new AsyncLocalStorage()
async function test() {
return storage.run({ test: 'vm' }, async () => {
console.log(storage.getStore());
await 42;
console.log(storage.getStore()); // this logs undefined
});
}
test()
`, context); the |
The AsyncLocalStorage instance may be created within that context, but the underlying call to Though even if you move the require into the If you try I do agree that the intent in that code sample is not to jump between contexts, but that is how it works currently and, more importantly, is how it worked long before the context-scoping of PromiseHooks. Like I said, async_hooks is leaking information into other contexts when it shouldn't. The PromiseHook change fixes some of that leaking, but there's still the rest of async_hooks leaking into other contexts where it should not. If we wanted to retain the old way of leaking async_hooks information into other scopes, we could probably do something to keep registered promise hook functions synchronized across all contexts. Personally I think that's a bad idea though and we should be working to context-scope everything properly. I would understand if wanted to have it leak the old way at least for the time being and then make the true context-scoping of everything a major change later. |
The problem is that the above breaks the usage of AsyncLocalStorage and Jest as it runs all tests in a VM - it's a significant regression that is not obvious for the end user. This should be fixed, or I fear we would have to revert the main optimization changes :/ - it's definitely needed for the new PromiseHooks to be backported to v14.
I fully agree with this approach. @nodejs/diagnostics wdyrt? |
We will have to work with the Jest team on this. Even if AsyncLocalStorage is changed to be context-aware, what is going to happen with promises created within core (for example using the /cc @SimenB |
Issue raised on Jest side: jestjs/jest#11435 |
I'm not sure if context scoped async hooks are applicable to all use cases. |
No, this issue means that AsyncLocalStorage would not work at all inside vm because the global hooks that AyncLocalStorage relies upon are outside of the context. |
I meant after we move whole async hooks to operate per context. |
How does it make sense to make async hooks per context, given that async operations can cross contexts? I feel like the promise hooks here should cover all contexts created by Node.js. |
Can we get the previous behavior back without reverting #36394 entirely? |
Like I said before, we could synchronize the registered hook functions across every created context. We'd have to store the functions and each created context to make sure that:
Still not sure I agree that hooks should broadcast across all contexts, though I intend on eventually ensuring we have sufficient higher-level APIs to just deprecate async_hooks as a public interface anyway, which would eliminate the security concern of leaking resources into other contexts. I'm not sure if I will have much time to work on this in the immediate term though...I'll see if I can figure something out. |
If we can't get a "quick" resolution, we might have to revert :(. |
Yeah. I'll figure out soon if I can rearrange some stuff to get time for this. |
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]>
Looks like @bengl is already working on something, but generally, yes, this is not hard to fix, so we should really not revert the original change here. |
Yes, I'll try to round out a PR from that commit (there's some cleanup to do, etc.) in the next day or so, time permitting. It's just manually synchronizing PromiseHooks across the main and vm.Context-created Contexts, using the AsyncHooks class to hold the list of Contexts and the JS hooks (for adding to newly created contexts). I'm happy to adjust the approach here if folks have other ideas. |
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: #36394 Fixes: #38781 Signed-off-by: Bryan English <[email protected]> PR-URL: #38821 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]> PR-URL: nodejs#38821 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]> PR-URL: nodejs#38821 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]> PR-URL: nodejs#38821 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]> PR-URL: nodejs#38821 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]> PR-URL: nodejs#38821 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]> PR-URL: nodejs#38821 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: #36394 Fixes: #38781 Signed-off-by: Bryan English <[email protected]> PR-URL: #38821 Backport-PR-URL: #38577 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: #36394 Fixes: #38781 Signed-off-by: Bryan English <[email protected]> PR-URL: #38821 Backport-PR-URL: #38577 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: #36394 Fixes: #38781 Signed-off-by: Bryan English <[email protected]> PR-URL: #38821 Backport-PR-URL: #38577 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
The new JS PromiseHooks introduced in the referenced PR are per v8::Context. This meant that code depending on them, such as AsyncLocalStorage, wouldn't behave correctly across vm.Context instances. PromiseHooks are now synchronized across the main Context and any Context created via vm.Context. Refs: nodejs#36394 Fixes: nodejs#38781 Signed-off-by: Bryan English <[email protected]> PR-URL: nodejs#38821 Backport-PR-URL: nodejs#38577 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
After #36394, the following test is broken:
Node 16.1.0:
Node 16.2.0:
The text was updated successfully, but these errors were encountered: