Readable._read is called multiple times synchronously · Issue #24919 · nodejs/node (original) (raw)

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:

function flow(stream) {
const state = stream._readableState;
debug('flow', state.flowing);
while (state.flowing && stream.read() !== null);
}

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.