whatwg / streams

Streams Standard
https://streams.spec.whatwg.org/
Other
1.35k stars 160 forks source link

Clarify: tee is unsafe for independent consumption since it backpressures to the faster consumer #1233

Open yonran opened 2 years ago

yonran commented 2 years ago

Unfortunately, the built-in tee algorithm backpressures to the faster consumer and enqueues chunks without limit to the slower consumer. Therefore, it is generally not safe to use when the two branches are read by independent consumers at different speed, since the consumer will eventually run out of memory.

I believe that this was an unfortunate design mistake because it conflicts with the suggestion in Stream requirements:. You must be able to pipe a stream to more than one writable stream. which said, “The tee stream can use a number of strategies to govern how the speed of its outputs affect the backpressure signals it gives off, but the simplest strategy is to pass aggregate backpressure signals directly up the chain, thus letting the speed of the slowest output determine the speed of the tee.” This also differs from analogous operations in other libraries such as repeated nodejs Readable.pipe or akka-streams Source.alsoTo which backpressure to the slower consumer and only require a bounded queue.

As I said in a node-fetch issue https://github.com/node-fetch/node-fetch/issues/1568, I think this unbounded enqueueing algorithm of ReadableStream.tee() from https://github.com/whatwg/streams/pull/311 was a mistake. The built-in operations of a ReadableStream should only need a fixed-size queue. , but at this point it is too late to fix it.

But at least we can clarify the informational text, which implied that it is safe to tee() a stream and consume it independently. It is generally not safe to consume a tee()’d stream independently unless the difference in consumed data between the faster consumer and the slower consumer fits in memory.

(See WHATWG Working Mode: Changes for more details.)


Preview | Diff