-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
x/net/http2: errors don't implement Temporary interface #35286
Comments
@bcmills what kind of help wanted? |
@kirillx, figure out which of the errors should be considered (The hard part of the CL to fix it is likely to be the documentation: it will need comments explaining why the errors are, in fact, temporary.) |
You can also see lots of such reports in github: BTW, why these errors are not exported? They are in x/net/http2 package, but seems like they are made somehow private during bundling to http/h2_bundle.go ... Exporting error types would make it possible checking for it's type at least and codes. Any ideas? |
... returning true. Justification from golang/go#35286 (#35286): 1. http.http2GoAwayError (e.g. 'http2: server sent GOAWAY and closed the connection; LastStreamID=8329, ErrCode=NO_ERROR, debug="max_age"') This error happens typically if server decides enough requests per connection serviced or after some timeout or graceful shutdown (https://http2.github.io/http2-spec/#GOAWAY). 2. http.http2StreamError with INTERNAL_ERROR code (e.g. 'stream error: stream ID 309; INTERNAL_ERROR') According to HTTP2 SPEC: INTERNAL_ERROR (0x2): The endpoint encountered an unexpected internal error. i.e. this error to be used similar to HTTP 500 and real-life experience clearly demonstrates it is retryable (like HTTP 500). Google Cloud SDK also implements retries on this error at cloud.google.com/go/storage/reader.go: if strings.HasSuffix(err.Error(), "INTERNAL_ERROR") && strings.Contains(reflect.TypeOf(err).String(), "http2") Signed-off-by: Kirill Korotaev <[email protected]>
Treating With human intervention, nearly any error can be “temporary” — the relevant question from an API perspective, I think, is whether the problem is likely to resolve on its own without intervention, and in the case of a 500 status that seems much less likely. Retrying a 500 without knowing its cause seems dubious at best — sometimes it will help, and sometimes it will only exacerbate a Query of Death. Given that it is easier for callers to add a retry than to remove one, that doesn't seem like a good place for the library to bias in favor of retrying. |
https://cloud.google.com/storage/docs/exponential-backoff
https://docs.aws.amazon.com/general/latest/gr/api-retries.html
|
“almost any cloud SDK and REST API” is not the same thing as “the HTTP protocol”. The |
It is exported from However, even that could potentially be remedied by exporting the type (or by transforming it to something exported) from within the |
I don't really want to argue about retriable errors. Protocol spec doesn't define it well, besides some basics like Retry-After headers and that streams after GoAway are retriable. Yet, none of the POSIX specs define that EMFILE and ETIMEDOUT are temporary errors, which are treated by Go so. From my POV per HTTP2 SPEC INTERNAL_ERROR is not smth which happens normally if all the parties obey the protocol. Thus this error is kind of temporary.
Does it still help when all the SDKs are using net/http? Am I missing smth? Would be thankful for details on how it helps with 3rd party packages.
Should I add
to export it? I can change the patch this way if you feel it is better suited. |
GOAWAY
Nothing in that seems to indicate "you should retry this". =) There are cases where a server might accept a retry, but we probably shouldn't design around "it happens sometimes". 500 Internal Server Error I spent a good deal of time researching this subject over the last two years. Myself and several engineers collaborate to create http://aip.dev/194, which lays out which RPC codes should retried and under which circumstances. Although http://aip.dev/194 is geared towards RPCs, some codes have easy HTTP corollaries: gRPC's
@kirillx , you mention But, I don't think the Go stdlib can guarantee that all 500 errors are temporary. I think this is WAI. If you know your API returns retryable 500, it's fairly easy to identify them. |
given |
What version of Go are you using (
go version
)?1.13
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (
go env
)?Linux
What did you do?
HTTP client application issuing std POST/GET requests.
What is wrong?
Sometimes http client returns the below errors and there is no good way to verify that they are temporary and might be retried:
a) http.http2GoAwayError (e.g. 'http2: server sent GOAWAY and closed the connection; LastStreamID=8329, ErrCode=NO_ERROR, debug="max_age"'
b) http.http2StreamError (e.g. 'stream error: stream ID 309; INTERNAL_ERROR')
After googling one can even find that some detect such errors and retry on them like in cloud.google.com/go/storage/reader.go:
if strings.HasSuffix(err.Error(), "INTERNAL_ERROR") && strings.Contains(reflect.TypeOf(err).String(), "http2") {
So if there is no objections I would make these 2 errors implement Temporary() interface returning true.
The text was updated successfully, but these errors were encountered: