Skip to content

Transform a parked TransformStream write after one backpressure wait - #7412

Open
jasnell wants to merge 1 commit into
mainfrom
jasnell/ts-streams-transform-write-stall
Open

jasnell wants to merge 1 commit into
mainfrom
jasnell/ts-streams-transform-write-stall

Conversation

@jasnell

@jasnell jasnell commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

The transform sink's write algorithm waited for the backpressure-change
promise in a loop, re-checking the flag after each wake-up. The spec
waits once: a read's pull releases the write, and an enqueue on a stored
controller in that same turn re-asserts backpressure before the write's
reaction runs, yet the write still transforms. Under the loop it parked
again until the next read, so a producer that awaited each write before
reading again deadlocked, and the transformer never saw the chunk. The
C++ implementation waits once.

Both sink writes now wait once and then check the writable for
erroring, as before. The zero-algorithm path's loop could never iterate
twice, since that readable has no controller to enqueue through; it
changes for uniformity.

Pinned in the transform suite's backpressure.js. The release through a
pending read is parity. The release through a dequeue at readable hwm 1
is a divergence (ledger #14): the C++ readable does not pull after a
dequeue that leaves room (readable ledger #5), so its write stays parked
until a read finds the queue empty. An error() in the release's turn is
a divergence too (ledger #15): the woken TypeScript write rejects with
the writable's stored error, the C++ one has already lost its writable
reference and algorithms and rejects with the identity path's enqueue
TypeError.

@jasnell
jasnell added this pull request to stack #7413 September 17, 2026 14:53
@jasnell
jasnell requested review from a team as code owners September 17, 2026 14:53
@jasnell
jasnell requested review from guybedford and npaun September 17, 2026 14:53
@ask-bonk

ask-bonk Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

LGTM

github run

Base automatically changed from jasnell/ts-streams-primordial-gaps to main September 17, 2026 16:29
The transform sink's write algorithm waited for the backpressure-change
promise in a loop, re-checking the flag after each wake-up. The spec
waits once: a read's pull releases the write, and an enqueue on a stored
controller in that same turn re-asserts backpressure before the write's
reaction runs, yet the write still transforms. Under the loop it parked
again until the next read, so a producer that awaited each write before
reading again deadlocked, and the transformer never saw the chunk. The
C++ implementation waits once.

Both sink writes now wait once and then check the writable for
erroring, as before. The zero-algorithm path's loop could never iterate
twice, since that readable has no controller to enqueue through; it
changes for uniformity.

Pinned in the transform suite's backpressure.js. The release through a
pending read is parity. The release through a dequeue at readable hwm 1
is a divergence (ledger #14): the C++ readable does not pull after a
dequeue that leaves room (readable ledger #5), so its write stays parked
until a read finds the queue empty. An error() in the release's turn is
a divergence too (ledger #15): the woken TypeScript write rejects with
the writable's stored error, the C++ one has already lost its writable
reference and algorithms and rejects with the identity path's enqueue
TypeError.
@jasnell
jasnell force-pushed the jasnell/ts-streams-transform-write-stall branch from 1ec78d5 to ae8979d Compare September 17, 2026 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant