Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been a while since I've worked on this but does this still function correctly in terms of updating the write queue size after the full write completes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@apapirovski I’ve thought about pinging you but didn’t see you around in IRC ;)
I would assume so, or at least assume that something in our suite tests that? Do you have an example of code to test this against?
Also, I have to admit that I’m still not 100 % clear on the semantics inside
Socket.prototype._onTimeout
… why do we care about the previous write queue size? If we do, why don’t we track that in JS rather than from C++? It’s very hard to follow the data flow for this property since it’s updated at some parts in the code, but it doesn’t really get clear which parts those are…There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a reason that was a bug in core for a great many years... 😆 (It got exacerbated when keep-alive timeouts were introduced and made to work properly but it was a major issue even before then, it just took a much longer write — over 120s — to discover it.)
Basically, since we hand off the write to C++, the JS side doesn't really know how the write is progressing while it's actually getting written to the socket. To get around that, the C++ code should only update the write state when it first starts and when it fully finishes (0 left). In between that, the JS code (within
_onTimeout
) is allowed to check on the C++ end to determine whether there has been any progress since the last time_writeQueueSize
changed. If not, we're dealing with a timeout. If yes, it's just a long running write.(Also, the current architecture around this is meant to prevent the C++ side from constantly updating JS objects with new info, so the
_onTimeout
checks itself so that these checks only happen very infrequently.)Does that make it a bit clearer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have/need/want any tests for that? I don’t think any of the tests take that long…
Yes, it does, thank you. 💙
What would you think about the following?
writeQueueSize
in JS when writing to a socket, e.g. storing it aslastKnownWriteQueueSize
lastKnownWriteQueueSize
with the current value and reschedule the timeoutUint32Array
rather than )Does that sound okay? I think that might be a bit easier to keep track off…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test that failed earlier tests for it, it just modifies the timeout value to make it shorter.
The thing it doesn't test for is whether the
writeQueueSize
gets reset down to 0 after the write is done. Maybe you could expand that test as part of this PR?I feel like I would prefer to keep the size updating to a minimum since it's not used in C++ and the timeouts aren't frequent. I would rather have a slightly slower
_onTimeout
that needs to make an extra check than do more work during all the other regular writes that won't ever trigger a timeout. (I don't think callingBIO_pending
constantly is free.)I wonder if there's a middle road here. I'll try to think on it tonight.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m not sure I follow – is the idea that we only track the write queue size on the JS object, refreshing it when writes happen or finish in JS, and in
_onTimeout
?Yay, thanks! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, basically just don't manage
writeQueueSize
in C++ at all. If_onTimeout
requests it then just return the updated value and then the JS can actually update the reference on the object.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, yeah, that sounds fine to me :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW this might be a bit tricker than I had originally imagined bc it's used by all the different wraps, like TTY, Pipe, etc. I might be changing quite a bit more about how all of this works than I had originally intended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kinda like hearing that, tbh ;) This PR wouldn’t have been the last refactoring by far, hopefully…