stream: reset awaitDrain after manual .resume()
Checklist
-
tests and code linting passes -
a test and/or benchmark is included -
the commit message follows commit guidelines
Affected core subsystem(s)
stream
Description of change
Reset the readableState.awaitDrain
counter after manual calls to .resume()
.
What might happen otherwise is that a slow consumer at the end of the pipe could end up stalling the piping in the following scenario:
- The writable stream indicates that its buffer is full.
- This leads the readable stream to
pause()
and increase itsawaitDrain
counter, which will be decreased by the writable’s nextdrain
event. - Something calls
.resume()
manually. - The readable continues to pipe to the writable, but once again the writable stream indicates that the buffer is full.
- The
awaitDrain
counter is thus increased again, but since it has now been increased twice for a single piping destination, the nextdrain
event will not be able to resetawaitDrain
to zero. - The pipe is stalled and no data is passed along anymore.
The solution in this commit is to reset the awaitDrain
counter to zero when resume()
is called.
Fixes: https://github.com/nodejs/node/issues/7159
This bug is has been around at least since 0.12, and I don’t currently know why it never popped up before #2325 when the awaitDrain
mechanism worked like it does today.
/cc @nodejs/streams