From 90231b26a12c5b050d3fc6443000a8fd151af8ba Mon Sep 17 00:00:00 2001 From: Dayun Date: Wed, 26 Aug 2026 16:34:19 +0900 Subject: [PATCH] stream: fix pipeline function tail deadlock Signed-off-by: Dayun --- lib/stream/promises.js | 12 +++++++++++- test/parallel/test-stream-pipeline.js | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/stream/promises.js b/lib/stream/promises.js index a8b65d62b096..43c378a20f22 100644 --- a/lib/stream/promises.js +++ b/lib/stream/promises.js @@ -1,6 +1,7 @@ 'use strict'; const { + ArrayIsArray, ArrayPrototypePop, Promise, } = primordials; @@ -28,13 +29,22 @@ function pipeline(...streams) { end = options.end; } - pl(streams, (err, value) => { + let lastStream = streams[streams.length - 1]; + if (streams.length === 1 && ArrayIsArray(streams[0])) { + lastStream = streams[0][streams[0].length - 1]; + } + + const stream = pl(streams, (err, value) => { if (err) { reject(err); } else { resolve(value); } }, { signal, end }); + + if (typeof lastStream === 'function' && stream.readable) { + stream.resume(); + } }); } diff --git a/test/parallel/test-stream-pipeline.js b/test/parallel/test-stream-pipeline.js index 8ee197b44e0b..861d330807ef 100644 --- a/test/parallel/test-stream-pipeline.js +++ b/test/parallel/test-stream-pipeline.js @@ -1657,6 +1657,22 @@ tmpdir.refresh(); })); } +{ + async function* passThrough(source) { + for await (const chunk of source) { + yield chunk; + } + } + + const streams = () => [ + Readable.from(Array.from({ length: 100 }, (_, i) => i)), + passThrough, + ]; + + pipelinep(...streams()).then(common.mustCall()); + pipelinep(streams()).then(common.mustCall()); +} + { const r = new Readable(); for (let i = 0; i < 4000; i++) {