Repository navigation
Duplex stream pipeline regression in 13 #32955
Copy link
Copy link
Closed
Description
Activity
I think this is related to #31940 as well
Equivalent test case using TCP
const net = require('net') const pipeline = require('stream').pipeline net.createServer(function (socket) { // echo server pipeline(socket, socket, () => {}) // 13 force destroys the socket before it has a chance to emit finish socket.on('finish', function () { console.log('finished only printed in node 12') }) }).listen(10000, function () { const socket = net.connect(10000) socket.end() })
cc @ronag
Seems to work on master. Checking v13-staging.
This is a problem on v13 only as far as I can tell.
Basically pre v14net.Sockethad a bit strange semantics regardingwritable/readablewhich kind of short-circuits thewritable/readablecheck which pipeline depends on.Looking into ways to get around this.
This happens in master on all streams that don't have autoDestroy enabled as well (ie any readable-stream stream or any stream that opt out)
const stream = require('stream') // duplex stream similar to a tcp stream etc const dup = new stream.Duplex({ autoDestroy: false, write (data, enc, cb) { cb() }, read () { this.push(null) }, destroy () { console.log('ws: am getting destroyed') }, final (cb) { console.log('ws: flushing writable...') setTimeout(function () { console.log('ws: done flushing writable...') cb() }, 1000) } }) // just some sink const sink = new stream.Writable({ write (data, enc, cb) { cb() } }) // pipe readable side stream.pipeline(dup, sink, function () { }) dup.write('test') dup.end()
Above prints the following
ws: flushing writable... ws: am getting destroyed ws: done flushing writable...Yes, I see the problem. Will try to prepare a PR by the end of the day. Thanks a lot @mafintosh!
- added 2 commits that reference this issue
on Apr 27, 2020 - added a commit that references this issue
on Jul 27, 2026
Metadata
Metadata
Assignees
Labels
No labels
What steps will reproduce the bug?
pipeline in 13 seems to destroy duplex streams before the get a change to finish their writable flus h (ws.end() -> ws._final) lifecycle.
I managed to boil it down to a pretty straightforward test case below
Running this produces:
Notice that the
dupstream gets destroyed before it has a chance to finish it's writable flush in the _final lifecycle, due to the pipeline auto destroying it in 13.