-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
ClientModel: Change approach to buffering response.Content #41080
Comments
Initial notes from work on #41693 and annelo-msft#13:
I am still working on an end-to-end solution to complete the feasibility assessment. |
Response.ContentProblemAzure.Core-based client protocol methods return The problem with throwing from the Since we plan to ship We discuss proposals to address this problem below and propose a solution based on this discussion at the end of this comment. Proposals1. Make Response.Content "always work"In this proposal:
Advantages:
Disadvantages:
2. Continue to throw from Response.Content
Advantages:
Disadvantages:
3. Add a tester to ResponseIn this approach, we use either option 1 or option 2 above, and we add a property Advantages:
Disadvantages:
4. Introduce a StreamingResponse typeIn this approach, we introduce a This would look as follows: public abstract class StreamingPipelineResponse {
Stream? ContentStream { get; set; }
}
public abstract class PipelineResponse : StreamingPipelineResponse {
// Inherits ContentStream
BinaryData Content { get; }
}
public abstract class Response : PipelineResponse {
// Inherits both ContentStream and Content
} Azure.Core protocol methods would need to return It may also not work with protocol methods on ClientModel-based clients. This is because ClientModel-based clients return Advantages:
Disadvantages:
RecommendationI recommend going with option 1 for the following reasons:
|
We settled on this as the public API for PipelineResponse: public abstract class PipelineResponse
{
public abstract Stream? ContentStream { get; set; }
public abstract BinaryData Content { get; }
public abstract BinaryData ReadContent(CancellationToken cancellationToken = default);
public abstract ValueTask<BinaryData> ReadContentAsync(CancellationToken cancellationToken = default);
} The tester provided is message.BufferResponse. This is sufficient for policies to check in order to know whether or not the response was buffered so they don't call ReadContent when holding a live network stream and load too much data into memory. End-users of protocol methods exposing live network streams are expected to read the documentation of the protocol method to know that it exposes a live network stream, and only call ReadContent to buffer it if they expect the response content to be small enough to load into memory. |
Problem Description
The APIs we have today in Azure.Core around Response.Content and Response.ContentStream and buffering are not transparent. It is not clear to the end-user which responses are buffered and which are not. The only way for users to discover this is to read the docs for a service method.
High-level proposal
Make a change to the current implementation of the PipelineResponse.Content property such that we no longer throw if the response has not been buffered (i.e. PipelineMessage.BufferResponse has been set to false by the client-author). This means that end-users can always access PipelineResponse.Content and if it is not buffered, it will buffer the response in the response.Content field. In the rare situation where response.Content is larger than what we can fit in memory, the user will either get an IOException or -- since we will have wrapped the live network stream in a ReadTimeoutStream -- the buffering will throw a TaskCanceledException due to the network timeout being applied.
Implementation proposal
(From @KrzysztofCwalina and under investigation per feasibility in #41693 and related PRs)
Prior notes
See this comment thread for details: #41016 (comment)
This issue tracks the work to change how response buffering works for ClientModel responses. @KrzysztofCwalina would like to optimize for buffered content in the BinaryData response.Content property and not retain the MemoryStream we used to buffer the content in the ContentStream property. In a greenfield scenario, this would be great, but with a lot of code built on top of Azure.Core's response.ContentStream property and the idea that Content throws if ContentStream doesn't hold the buffered MemoryStream, we would likely need to go through breaking change review with the arch board to assess the feasibility of this change.
A proposed implementation that helps identify the CI tests that are affected by this change can be found here: #41047
The text was updated successfully, but these errors were encountered: