Skip to content

stream: destroy duplex on early return in Duplex.from(asyncFn)#62953

Open
maruthang wants to merge 1 commit intonodejs:mainfrom
maruthang:fix-55077-duplexify-destroy-upstream
Open

stream: destroy duplex on early return in Duplex.from(asyncFn)#62953
maruthang wants to merge 1 commit intonodejs:mainfrom
maruthang:fix-55077-duplexify-destroy-upstream

Conversation

@maruthang
Copy link
Copy Markdown

When Duplex.from(asyncFn) is given an async function (gen)
that returns without consuming all of gen, the duplex never
reached final, so the pipeline kept pumping writes that never
completed and the upstream Readable was never destroyed.

Track whether final() has been called via a finalized flag.
When the user's promise resolves and final has not been
called, call destroyer(d) on the duplex so the existing eos
handler propagates destruction upstream.

The async-iterable branch (isIterable(value)) and the
rejection path are unmodified, so the regression that caused
PR #55096 to be reverted by PR #56278 is preserved.

Fixes: #55077


Note: I was unable to run the test suite locally (no built out/Release/node on this Windows host). The touched JS lints clean and passes node --check. The PR #56278 regression scenario was carefully preserved by leaving the isIterable(value) branch untouched. Looking forward to CI verification — please flag any concern about reintroducing PR #56278's regression.

When `Duplex.from(asyncFn)` is given an `async function (gen)`
that returns without consuming all of `gen`, the duplex never
reached `final`, so the pipeline kept pumping writes that never
completed and the upstream Readable was never destroyed.

Track whether `final()` has been called via a `finalized` flag.
When the user's promise resolves and `final` has not been
called, call `destroyer(d)` on the duplex so the existing `eos`
handler propagates destruction upstream.

The async-iterable branch (`isIterable(value)`) and the
rejection path are unmodified, so the regression that caused
PR nodejs#55096 to be reverted by PR nodejs#56278 is preserved.

Fixes: nodejs#55077
Signed-off-by: Maruthan G <[email protected]>
@nodejs-github-bot
Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/streams

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. stream Issues and PRs related to the stream subsystem. labels Apr 25, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.64%. Comparing base (21436f0) to head (8a7adc0).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #62953      +/-   ##
==========================================
- Coverage   89.66%   89.64%   -0.03%     
==========================================
  Files         706      706              
  Lines      219391   219399       +8     
  Branches    42068    42067       -1     
==========================================
- Hits       196712   196672      -40     
- Misses      14578    14631      +53     
+ Partials     8101     8096       -5     
Files with missing lines Coverage Δ
lib/internal/streams/duplexify.js 96.97% <100.00%> (+0.06%) ⬆️

... and 32 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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. stream Issues and PRs related to the stream subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stream not destroyed when piped in Duplex.from() writable

2 participants