stream: keep async context of parked writes by mcollina · Pull Request #66907 · nodejs/node · GitHub
Skip to content

stream: keep async context of parked writes - #66907

Open
mcollina wants to merge 1 commit into
nodejs:mainfrom
mcollina:webstreams-parked-write-async-context
Open

mcollina wants to merge 1 commit into
nodejs:mainfrom
mcollina:webstreams-parked-write-async-context

Conversation

@mcollina

Copy link
Copy Markdown
Member

A TransformStream write that parks on backpressure is resumed by the read that lifts the backpressure (transformStreamSetBackpressure(stream, false) enqueues writeContinuation). Since #65143/#65625 that meant transform() for the parked chunk, every write queued behind it (the continuation now attaches the writable controller's writeFulfilled/writeRejected), and finally flush() ran in the reader's async context instead of the writer's.

This captures the AsyncContextFrame when the write parks and restores it while the continuation runs, so the perform-transform call and the write reactions are registered in the same context the spec's [[backpressureChangePromise]] reaction had. The continuation still runs at the same microtask position.

Issue repro, before/after:

before: a:none b:none c:none d:none e:none flush:none
after:  a:writer b:writer c:writer d:writer e:writer flush:writer

The reverse direction was also broken (not reported in the issue): with the pipe started outside any store and the reader inside als.run('reader'), transform()/flush() saw reader. The new test covers both.

benchmark/webstreams/pipe-through.js (10 runs) shows no significant change (default +0.33% ±4.16%, transform -2.43% ±2.89%).

Backport note: v24.x and v26.x still have the async_hooks-based AsyncLocalStorage (--no-async-context-frame, removed on main in #63641), where the issue also reproduces. Backports need an extra fallback for that mode, e.g. reverting to promise-based parking when async hooks are enabled.

Fixes: #66906

🤖 Generated with Claude Code

https://claude.ai/code/session_01LGUJ9PwPYkYJiCpUEsr7KJ

A TransformStream write that parks on backpressure was resumed from
the read that lifted the backpressure, so transform(), the writes
queued behind it, and flush() ran in the reader's async context
instead of the writer's. Capture the async context frame when the
write parks and restore it while the continuation runs, matching the
context the spec's [[backpressureChangePromise]] reaction had.

Fixes: nodejs#66906

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGUJ9PwPYkYJiCpUEsr7KJ
Signed-off-by: Matteo Collina <hello@matteocollina.com>
@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. web streams Issues and PRs related to the Web Streams API. labels Oct 21, 2026
@codecov

codecov Bot commented Oct 21, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-ci PRs that need a full CI run. web streams Issues and PRs related to the Web Streams API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

webstreams: transform() loses AsyncLocalStorage context after a parked write (regression in v24.22.0)

2 participants