Description
- Version: v10.10.0, v11.4.0
- Platform: Linux 4.4.0-45-generic deprecate domains #66-Ubuntu SMP Wed Oct 19 14:12:37 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
- Subsystem: stream
The documentation for readable._read(size)
states the following:
readable._read()
is guaranteed to be called only once within a synchronous execution, i.e. a microtick.
However the following example demonstrates starvation if that method is able to push all of its data synchronously. The stream implementation ends up calling the read-function repeatedly and won't yield execution as documented.
var Readable = require('stream').Readable;
let c = 10;
let r = new Readable({
read: () => {
process.nextTick(console.log, 'next-tick');
r.push('a');
}
});
r.on('data', () => {});
process.nextTick(console.log, 'Got food'); // Never printed.
console.log('Requested food');
I believe the issue is caused by the flow
function calling stream.read
repeatedly within a while-loop until the stream fails to return data:
Lines 933 to 937 in 951b1c3
One option for fixing this might be to make flow
recurse with next tick:
function flow(stream) {
const state = stream._readableState;
debug('flow', state.flowing);
flow_(stream, state);
}
function flow_(stream, state) {
if(state.flowing && stream.read() !== null)
process.nextTick(flow_, stream, state);
}
Alternatively just updating the documentation might also work. I guess most streams that would encounter the issue would just delay r.push()
into the next tick as a workaround.
Even in my case this was just something I spotted while looking into #24918. I don't personally have a use case for such a stream.