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

Pausable chunked HTTP responses #104851

Conversation

DaveCTurner
Copy link
Contributor

Today we must collect together in memory everything needed to send a
HTTP response before starting to send it to the client, even if we're
using the chunked transfer encoding to bound the memory needed for the
final serialization step.

To properly bound the memory usage on the coordinating node we must
instead be able to start sending the response to the client before we
have collected everything needed to finish it. If we do this then we
must be able to handle the case where we run out of data to send by
pausing the transmission and resuming it once there's more data to send.

This commit extends the ChunkedRestResponseBody interface to allow it
to express that it has run out of chunks for immediate transmission, but
that the body will continue at a later point.

Today we must collect together in memory everything needed to send a
HTTP response before starting to send it to the client, even if we're
using the `chunked` transfer encoding to bound the memory needed for the
final serialization step.

To properly bound the memory usage on the coordinating node we must
instead be able to start sending the response to the client before we
have collected everything needed to finish it. If we do this then we
must be able to handle the case where we run out of data to send by
pausing the transmission and resuming it once there's more data to send.

This commit extends the `ChunkedRestResponseBody` interface to allow it
to express that it has run out of chunks for immediate transmission, but
that the body will continue at a later point.
@DaveCTurner DaveCTurner added >non-issue WIP :Distributed Coordination/Network Http and internode communication implementations v8.13.0 labels Jan 29, 2024
@DaveCTurner DaveCTurner marked this pull request as ready for review January 30, 2024 12:01
@DaveCTurner
Copy link
Contributor Author

This is ready to review. However, it has no concrete use cases yet so I'm undecided about whether to merge it now or wait until we actually need it for something. Opinions welcome.

@nik9000
Copy link
Member

nik9000 commented Jan 30, 2024

I could try to get some forms of ES|QL's response to come back with it before too long. The Arrow support in #104877 probably won't be soon. But we could use it for the "row-based" or "text" responses from ES|QL.

Copy link
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not read the tests closely yet. The main code change looks fine to me within my range of understanding.

Could you please confirm that the change should not increase the duration that a channel is held for completing a response? Today, a channel associated to the client request cannot do anything else before the response is fully computed. With this change, we amortize the channel waiting time throughout the response computation so that it is able to send out partial response more quickly without increasing the total time needed for complete processing.

@DaveCTurner
Copy link
Contributor Author

Could you please confirm that the change should not increase the duration that a channel is held for completing a response? Today, a channel associated to the client request cannot do anything else before the response is fully computed. With this change, we amortize the channel waiting time throughout the response computation so that it is able to send out partial response more quickly without increasing the total time needed for complete processing.

Right. Or at least, this PR doesn't change anything, there are no actions in production which use the pausability yet. But if we made an existing action pausable then it could start sending its response sooner than it does today, but it'd still take the same amount of work to finish computing & sending the response.

Copy link
Contributor

@henningandersen henningandersen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Relying a bit on Yang's thorough test review, though i skimmed and it looks like a reasonable set of tests for this.

@@ -39,10 +43,36 @@ public interface ChunkedRestResponseBody {
Logger logger = LogManager.getLogger(ChunkedRestResponseBody.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should change the name of this interface to ChunkedRestResponseBodyPart? That would make isDone less ambiguous (naming-wise). We could also rename isDone to isPartDone to make this more explicit.

I think the javadoc above could also be improved to mention that it can be multi-part.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++ I will do this in a follow-up to avoid introducing too much noise here. I pushed 4570c92 to improve the Javadocs here tho.

@DaveCTurner DaveCTurner added the auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) label May 27, 2024
@elasticsearchmachine elasticsearchmachine merged commit 6312d49 into elastic:main May 27, 2024
15 checks passed
@DaveCTurner DaveCTurner deleted the 2024/01/29/pausable-chunked-responses branch May 27, 2024 08:27
DaveCTurner added a commit to DaveCTurner/elasticsearch that referenced this pull request May 27, 2024
Follow-up to elastic#104851 to rename some symbols to reflect that the class
formerly known as a `ChunkedRestResponseBody` may now only be _part_ of
the whole response body.
elasticsearchmachine pushed a commit that referenced this pull request May 27, 2024
Follow-up to #104851 to rename some symbols to reflect that the class
formerly known as a `ChunkedRestResponseBody` may now only be _part_ of
the whole response body.
DaveCTurner added a commit to DaveCTurner/elasticsearch that referenced this pull request Jun 10, 2024
The listener supplied to `getNextPart()` may be completed in a
non-default thread context, and this trips assertions about thread
context pollution in the transport layer, so this commit adds the
missing protection against that.

Also the listener supplied to `getNextPart()` may be completed
immediately on the transport thread, which could lead to a stack
overflow, so this commit adds another `execute()` call to
unconditionally fork a fresh task.

Relates elastic#104851
@DaveCTurner DaveCTurner restored the 2024/01/29/pausable-chunked-responses branch June 17, 2024 06:17
DaveCTurner added a commit to DaveCTurner/elasticsearch that referenced this pull request Jun 17, 2024
Follow-up to elastic#104851 to rename some symbols to reflect that the class
formerly known as a `ChunkedRestResponseBody` may now only be _part_ of
the whole response body.
DaveCTurner added a commit that referenced this pull request Jun 17, 2024
The listener supplied to `getNextPart()` may be completed in a
non-default thread context, and this trips assertions about thread
context pollution in the transport layer, so this commit adds the
missing protection against that.

Also the listener supplied to `getNextPart()` may be completed
immediately on the transport thread, which could lead to a stack
overflow, so this commit adds another `execute()` call to
unconditionally fork a fresh task.

Relates #104851
DaveCTurner added a commit to DaveCTurner/elasticsearch that referenced this pull request Jun 17, 2024
Adds a utility for implementing REST APIs which construct a streaming
(i.e. pretty-much-constant-memory) `.zip` file response as a (pausable)
sequence of `ChunkedRestResponseBodyPart` instances, where each entry in
the `.zip` file is itself a (pausable) sequence of
`ChunkedRestResponseBodyPart` instances.

Relates elastic#104851
elasticsearchmachine pushed a commit that referenced this pull request Aug 7, 2024
Adds a utility for implementing REST APIs which construct a streaming
(i.e. pretty-much-constant-memory) `.zip` file response as a (pausable)
sequence of `ChunkedRestResponseBodyPart` instances, where each entry in
the `.zip` file is itself a (pausable) sequence of
`ChunkedRestResponseBodyPart` instances.

Relates #104851
rjernst pushed a commit to rjernst/elasticsearch that referenced this pull request Aug 7, 2024
Adds a utility for implementing REST APIs which construct a streaming
(i.e. pretty-much-constant-memory) `.zip` file response as a (pausable)
sequence of `ChunkedRestResponseBodyPart` instances, where each entry in
the `.zip` file is itself a (pausable) sequence of
`ChunkedRestResponseBodyPart` instances.

Relates elastic#104851
mhl-b pushed a commit that referenced this pull request Aug 8, 2024
Adds a utility for implementing REST APIs which construct a streaming
(i.e. pretty-much-constant-memory) `.zip` file response as a (pausable)
sequence of `ChunkedRestResponseBodyPart` instances, where each entry in
the `.zip` file is itself a (pausable) sequence of
`ChunkedRestResponseBodyPart` instances.

Relates #104851
cbuescher pushed a commit to cbuescher/elasticsearch that referenced this pull request Sep 4, 2024
Adds a utility for implementing REST APIs which construct a streaming
(i.e. pretty-much-constant-memory) `.zip` file response as a (pausable)
sequence of `ChunkedRestResponseBodyPart` instances, where each entry in
the `.zip` file is itself a (pausable) sequence of
`ChunkedRestResponseBodyPart` instances.

Relates elastic#104851
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-merge-without-approval Automatically merge pull request when CI checks pass (NB doesn't wait for reviews!) :Distributed Coordination/Network Http and internode communication implementations >non-issue Team:Distributed (Obsolete) Meta label for distributed team (obsolete). Replaced by Distributed Indexing/Coordination. v8.15.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants