Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Readable event triggers but socket.readableLength returns zero #40136

Closed
davidkjackson54 opened this issue Sep 17, 2021 · 20 comments
Closed

Readable event triggers but socket.readableLength returns zero #40136

davidkjackson54 opened this issue Sep 17, 2021 · 20 comments
Labels
doc Issues and PRs related to the documentations. good first issue Issues that are suitable for first-time contributors. net Issues and PRs related to the net subsystem. stream Issues and PRs related to the stream subsystem.

Comments

@davidkjackson54
Copy link

davidkjackson54 commented Sep 17, 2021

Version

16.4.2

Platform

Windows 10

Subsystem

No response

What steps will reproduce the bug?

I am reading specific lengths of data off the readable queue. I check the readableLength to determine how much data I can read.
However, there are occasions when the readable event triggers but the readableLength is returned as zero.

client._socket.on("readable", () => {
        console.log("Readable event triggered");
        console.log(
          `${new Date().toLocaleString()}, Readable Stream has ${client._socket.readableLength} bytes of data available`
        );
        if (client._socket.readableLength === 0) {
          // for some reason the readable event can trigger but there be nothing in the readable queue
          console.log("readable queue is empty");
          return;
        }

How often does it reproduce? Is there a required condition?

This typically happens when TCP has decided to chunk the return of the data. I read what is available then wait for the next readable event to fire, then I find that the readableLength is zero - despite the readable event having triggered.

What is the expected behavior?

readableLength should contain the number of bytes available in the stream after the readable event has triggered.

What do you see instead?

Readable event triggered
9/17/2021, 7:47:19 AM, Readable Stream has 0 bytes of data available
readable queue is empty

Additional information

No response

@davidkjackson54 davidkjackson54 changed the title Using node net readable event triggers but socket.readableLength returns zero Readable event triggers but socket.readableLength returns zero Sep 17, 2021
@VoltrexKeyva VoltrexKeyva added the net Issues and PRs related to the net subsystem. label Sep 17, 2021
@ronag
Copy link
Member

ronag commented Sep 17, 2021

I believe 'readable' can also be emitted when the stream has "ended", i.e. readableEnded is true.

@ronag
Copy link
Member

ronag commented Sep 17, 2021

@nodejs/streams I think we have an edge case where an empty buffer can cause readable to be emitted... we should probably ignore empty chunks?

@ronag
Copy link
Member

ronag commented Sep 17, 2021

I don't think this is a bug though...

@davidkjackson54
Copy link
Author

I have the "end" event in place but I am not seeing it being triggered.
How can the readable event be triggered when there is nothing to actually read?? That seems like a bug to me..
Otherwise it would appear to defeat the purpose of the event.

Thee doc states:
Event: 'readable'#
History
The 'readable' event is emitted when there is data available to be read from the stream. In some cases, attaching a listener for the 'readable' event will cause some amount of data to be read into an internal buffer.

@ronag ronag added the stream Issues and PRs related to the stream subsystem. label Sep 18, 2021
@mcollina
Copy link
Member

Consider this example:

const { Readable } = require('stream')

const r = new Readable({
  read () {}
})

r.on('readable', function () {
  console.log('readable', r.read())
})

r.on('end', function () {
  console.log('end')
})

r.push(null)

null implies EOF and it will trigger 'readable' and 'end'.
There is something to read on the stream, the end of it.

I think we could improve the docs.

@mcollina mcollina added doc Issues and PRs related to the documentations. good first issue Issues that are suitable for first-time contributors. labels Sep 21, 2021
@lpinca
Copy link
Member

lpinca commented Sep 21, 2021

I have the "end" event in place but I am not seeing it being triggered.

@davidkjackson54 are you are to write a reproducible example using only Node.js core modules?

@davidkjackson54
Copy link
Author

davidkjackson54 commented Sep 21, 2021

Unfortunately, it would be quite difficult to create a recreation scenario.
However, as I say, I do have the 'end' event in place and it is not being triggered.
Also, as I mentioned above, despite the readable event being triggered, I am now having to check the length of socket.readableLength and manage it.

I honestly think that it should not trigger the readable event when there is no actual data to read as signified by a readableLength of zero being returned.

@axaysushir
Copy link

Should I take this issue? Also, can anyone suggest to me how to get started with this?

@jasnell
Copy link
Member

jasnell commented Sep 23, 2021

@ronag or @mcollina may have some ideas.

@mcollina
Copy link
Member

In https://github.com/nodejs/node/blob/master/doc/api/stream.md#event-readable, we mention

The 'readable' event will also be emitted once the end of the stream data has been reached but before the 'end' event is emitted.

We should note that this implies that .read() will return null in that case.

@axaysushir
Copy link

Ok, I'll look at it

@davidkjackson54
Copy link
Author

As I say, the end event is not being fired... when the zero length readable event has fired.

@mcollina
Copy link
Member

@davidkjackson54 unfortunately we cannot help unless you can produce a script to reproduce the problem you are facing.

Calling .read() will cause end to be emitted.

@davidkjackson54
Copy link
Author

It is not possible due to the data that I am retrieving,. This is coming from an IBM mainframe via TCP sockets and I cannot carve out the code to a recreated scenario.
As I say , the 'readable' event is being triggered and the socket.readableLength from that is coming back as zero. No 'end' event is being triggered for that particular situation.

@davidkjackson54
Copy link
Author

davidkjackson54 commented Sep 25, 2021 via email

@vweevers
Copy link
Contributor

Per the doc- readable infers something to read. Nothing to read if the readable length is zero is the way I interpret that

Readable infers new information. This is explained in the documentation:

The 'readable' event is emitted when there is data available to be read from the stream. [..] The 'readable' event will also be emitted once the end of the stream data has been reached but before the 'end' event is emitted. [..] Effectively, the 'readable' event indicates that the stream has new information: either new data is available or the end of the stream has been reached. In the former case, stream.read() will return the available data. In the latter case, stream.read() will returnnull.

Note @mcollina, this means there's no need for #40136 (comment). Everything stated in this thread is also present in documentation. But it could be improved by reordering the sentences, to give more information up front. For example:

The 'readable' event is emitted when there is data available to be read from the stream or when the end of the stream has been reached. Effectively, the 'readable' event indicates that the stream has new information. If data is available, stream.read() will return that data. [..] If the end of the stream data has been reached, calling stream.read() will return null, which in turn triggers the 'end' event.

@mcollina
Copy link
Member

That would be perfect @vweevers.

@davidkjackson54
Copy link
Author

davidkjackson54 commented Sep 25, 2021 via email

@davidkjackson54
Copy link
Author

davidkjackson54 commented Sep 26, 2021 via email

@mcollina
Copy link
Member

Yes, it does emit 'end' when stream.read(0) is called.

const { Readable } = require('stream')

const r = new Readable({
  read () {}
})

r.on('readable', function () {
  console.log('readable', r.read(0))
})

r.on('end', function () {
  console.log('end')
})

r.push(null)

targos pushed a commit that referenced this issue Oct 4, 2021
Fixes: #40136

PR-URL: #40212
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Anto Aravinth <anto.aravinth.cse@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
doc Issues and PRs related to the documentations. good first issue Issues that are suitable for first-time contributors. net Issues and PRs related to the net subsystem. stream Issues and PRs related to the stream subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants