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

Fix "http: read on closed response body" error #8332

Merged

Conversation

Jonathan-Rosenberg
Copy link
Contributor

@Jonathan-Rosenberg Jonathan-Rosenberg commented Oct 31, 2024

Closes #8331

Change Description

The current custom error handler is doing redundant work that eventually causes the read on closed response body.

Current Flow

  1. Using the retryable client, the generated code issues a request.
  2. If the response is retryable, it is retried until the attempts are exhausted.
  3. If none of the requests pass, and the error handler isn't nil (it's not), the error handler is called.
  4. The custom error handler drains the response's body, closes it, and returns the response along with the passed error (which is nil).
  5. The wrapping generated code will parse the response and then it will try to read its body. At this point, it will return the "read on closed response body" error.

Example for generated code from point 5:

// ParsePostStatsEventsResponse parses an HTTP response from a PostStatsEventsWithResponse call
func ParsePostStatsEventsResponse(rsp *http.Response) (*PostStatsEventsResponse, error) {
	bodyBytes, err := ioutil.ReadAll(rsp.Body)
	defer rsp.Body.Close()
	if err != nil {
		return nil, err
	}
.....

Removing the custom error handler will not affect the current usage which will behave as we expect. This is because the behavior of the default retry client is to drain the body and return an error without the response. That way the generated code will not try to read the response, but will return an error...

@Jonathan-Rosenberg Jonathan-Rosenberg added the include-changelog PR description should be included in next release changelog label Oct 31, 2024
Copy link

E2E Test Results - DynamoDB Local - Local Block Adapter

13 passed

Copy link

github-actions bot commented Oct 31, 2024

E2E Test Results - Quickstart

11 passed

Copy link
Member

@N-o-Z N-o-Z left a comment

Choose a reason for hiding this comment

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

Why are we not logging the number of attempts anymore?

@Jonathan-Rosenberg
Copy link
Contributor Author

@N-o-Z the opposite, we now start logging them in case of an error

@N-o-Z
Copy link
Member

N-o-Z commented Oct 31, 2024

@N-o-Z the opposite, we now start logging them in case of an error

I might be color blind... 😅

Copy link
Contributor

@arielshaqed arielshaqed left a comment

Choose a reason for hiding this comment

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

I don't understand why this fixes an issue.

  1. The docs explicitly say "If overriding this, be sure to close the body if needed.". We closed the body. How does this create a double-close?

  2. The comment for the behaviour of customErrorHandler says:

     // We need to consume response bodies to maintain http connections, but
     // limit the size we consume to respReadLimit.

    IIUC this means that we lose this behaviour. Why is this a good thing? Doesn't it mean retries will be much slower?

Not blocking or approving because I don't understand this PR. Will be happy to change this.

@Jonathan-Rosenberg
Copy link
Contributor Author

@arielshaqed

  1. I think that the notable two words in the provided section in the docs are if needed. We already drain the body and close it in the wrapping generated code. The problem isn't a double close, but a close and then a read by the generated client (as mentioned in the description and shown in the example). The error handler closes the body, and then the generated client tries to read it before it closes it as well (but it fails on the read!).
  2. In case of exhausted retries the retryable client itself drains the body with respReadLimit = int64(4096). The provided comment is actually a copy of the code that does that in the retryable client default implementation. The difference is that the retryable client doesn't return a response (as opposed to the custom error handler), but an error (check out the last section in the description after the example)

@Jonathan-Rosenberg Jonathan-Rosenberg merged commit c606279 into master Oct 31, 2024
38 checks passed
@Jonathan-Rosenberg Jonathan-Rosenberg deleted the fix/retryable-client/remove-custom-error-handler branch October 31, 2024 15:24
Copy link
Contributor

@arielshaqed arielshaqed left a comment

Choose a reason for hiding this comment

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

IIUC the issue is that customErrorHandler - which tries to prevent detailing the error message - has a bug and returns the response.

LGTM!

@Jonathan-Rosenberg
Copy link
Contributor Author

This is truly a bug, but the bigger picture is that this code is redundant and adds no value.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
include-changelog PR description should be included in next release changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: http: read on closed response body error
4 participants