Skip to content

src: keep ALS store in AsyncResource::MakeCallback - #66326

Draft
nigrosimone wants to merge 1 commit into
nodejs:mainfrom
nigrosimone:async-resource-frame
Draft

nigrosimone wants to merge 1 commit into
nodejs:mainfrom
nigrosimone:async-resource-frame

Conversation

@nigrosimone

@nigrosimone nigrosimone commented Sep 26, 2026 •

Copy link
Copy Markdown

AsyncResource saves the async context frame when it is created, and MakeCallback() enters it with async_context_frame::Scope. Then node::MakeCallback() opens the callback scope with an undefined frame, so the callback never runs in the saved one. Since AsyncContextFrame is the default (v24), AsyncLocalStorage loses its store in the callbacks of node::AsyncResource. With --no-async-context-frame the store is there.

Now MakeCallback() passes the saved frame to InternalMakeCallback(), as the Node-API AsyncContext already does. The Scope goes away, so every call also saves two Environment lookups and a global handle.

The new test fails without the change: the store is undefined in the callback.

Draft until #66316 lands: then I add an AsyncResource case to its make_callback benchmark. On top of #66316, with that case: from 198-205 ns to 153-157 ns per call.

Refs: #66316
Refs: #43038
Refs: nodejs/performance#24

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Sep 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Welcome to Node.js, and thank you for your first contribution!

Before review, please take a moment to read:

Please make sure every commit is signed off. For a first pull request, GitHub Actions require collaborator approval and Jenkins CI must be started by a collaborator or triager, so an initial wait is normal.

AsyncResource saves the async context frame when it is created, and
MakeCallback() enters it with async_context_frame::Scope. Then
node::MakeCallback() opens the callback scope with an undefined frame,
so the callback never runs in the saved one. Since AsyncContextFrame is
the default, AsyncLocalStorage loses its store in these callbacks.

Pass the saved frame to InternalMakeCallback(), as the Node-API
AsyncContext already does. This also removes the Scope from every call,
with its two Environment lookups and its global handle.

Refs: nodejs#66316
Refs: nodejs#43038
Refs: nodejs/performance#24
Signed-off-by: Nigro Simone <nigro.simone@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants