-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
net, os: Set*Deadline() expiration error should be unique, as .Timeout() is true for keepalive, etc #31449
Comments
Also filed #31490 to report that tls.DialWithDialer() doesn't respect .KeepAlive. |
It is documented that we enable keep-alives if that field is unset/zero. The choice of not specifying 15s in the docs was deliberate and is actually documented in the commit message: 5bd7e9c |
I believe this is a new bug in 1.12, so a fix should be backported to a 1.12.x release. cc @ianlancetaylor |
Do you know what makes this new in 1.12? I'm not seeing it. |
This decided on keepalive by default in 1.12: #23459. That causes deadline handlers in existing code to see non-deadline (i.e. keepalive) errors. |
If I understand you correctly, you are saying that the bug has existed for a long time for programs that enable TCP keepalive by setting the |
Yes. It's probably rare to use both deadlines and explicit keepalive, so the bug wasn't reported. Now any code with long deadlines (relatively common) will wrongly detect deadline events due to implicit keepalive. |
Go 1.13 also enables Keep-Alives by default on the net.Listen side (1abf3aa), so this might be worth fixing now, before exposing a new wave of applications to it. |
@costela, your keepalive patch will trigger this bug... @gopherbot please open backport 1.12 |
Backport issue(s) opened: #33137 (for 1.12). Remember to create the cherry-pick CL(s) as soon as the patch is submitted to master, according to https://golang.org/wiki/MinorReleases. |
I can't seem to find anything in the docs saying that a keepalive timeout should not set This isn't to say the new default behavior wouldn't introduce a potentially breaking change, but I'm not sure changing the error to be |
Docs say "A zero value for [deadline] means I/O operations will not time out." Don't worry about it; it's been assigned. Sorry to bother you. |
Deadlines and keep-alive errors are deeply different: the former are fully recoverable, the latter aren't, for example. It seems unlikely any code would ever want to handle them the same way. Keep-alives are more akin to the connection dropping, so I don't think marking them as Timeouts makes sense. I'll make this change tomorrow. |
@FiloSottile, let's make the Also I opened a 1.12.x backport issue. |
I looked into this, and as far as I can tell, there is no way to single out keep-alive errors: they just surface a ETIMEDOUT from the What we might do, is isolate deadline errors, which as far as I can tell (although I am no expert on that part of the code) are handled by runtime timers, and make those more uniquely recognizable. For example, by making them an exported error type. We might even decide to make only those have If I'm right, this is not a small fix to a specific error value anymore, and I don't think it's something we should ship at the very end of the freeze. /cc @golang/osp-team |
I believe that if a read from a network connection fails due to a deadline, the read will return |
Seems a fair bit simpler to change |
Back in #31449 (comment), I wrote:
We did not get into this, and we are close to the freeze. It seems like we should probably put this off to next cycle. But I will retitle so it is easier to understand what this is about. |
Above @rsc suggests that we change I suggest that we instead add |
Actually, let's just add |
Maybe go vet should flag use of err.Timeout() after Set*Deadline(), since that is not a reliable way to check for deadline-expired. Why is this error related to package EDIT: I forgot that deadlines also exist for os.File. |
Change https://golang.org/cl/228644 mentions this issue: |
Any change to "go vet" can be a separate issue. Although I suspect that that change is not feasible as it would make some amount of existing code non-vet-compliant, which we can't really do. The os package has |
Could Filed #38508 for the vet issue. |
Sure, we could have both |
It avoids the need to Almost all code using Set*Deadline() now needs to be updated. It's odd that those changes should require an import unless "os" is already imported. |
My guess is that very little code that uses I would like to hear someone else's opinion on this question. |
Change https://golang.org/cl/228645 mentions this issue: |
Ian's CL seems worth trying. Let's just be ready to roll it back if there are problems. |
If an I/O operation fails because a deadline was exceeded, return os.ErrDeadlineExceeded. We used to return poll.ErrTimeout, an internal error, and told users to check the Timeout method. However, there are other errors with a Timeout method that returns true, notably syscall.ETIMEDOUT which is returned for a keep-alive timeout. Checking errors.Is(err, os.ErrDeadlineExceeded) should permit code to reliably tell why it failed. This change does not affect the handling of net.Dialer.Deadline, nor does it change the handling of net.DialContext when the context deadline is exceeded. Those cases continue to return an error reported as "i/o timeout" for which Timeout is true, but that error is not os.ErrDeadlineExceeded. Fixes golang#31449 Change-Id: I0323f42e944324c6f2578f00c3ac90c24fe81177 Reviewed-on: https://go-review.googlesource.com/c/go/+/228645 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]>
Change https://golang.org/cl/239705 mentions this issue: |
After CL 228645 some mentions of the Deadline methods referred to the Timeout method, and some to os.ErrDeadlineExceeded. Stop referring to the Timeout method, to encourage ErrDeadlineExceeded. For #31449 Change-Id: I27b8ff34f31798f38b06437546886af8cce98ca4 Reviewed-on: https://go-review.googlesource.com/c/go/+/239705 Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Damien Neil <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
This is a bug. A keepalive error is a connection failure, not a deadline event.
net Docs say:
For a TLS connection that's been severed, Conn.Read() returns a net.Error with
.Timeout()==true
due to KeepAlive failure. (Go 1.12, Linux, amd64)The Error should give
.Timeout()==false
to comply with the docs. Code that checks for.Timeout()==true
would generally assume that an explicit deadline had passed.The
.Error()
string should mention keepalive. It's currently:"read tcp n.n.n.n:p->n.n.n.n:p: read: connection timed out"
Related: net.Dialer.KeepAlive gets 15*time.Second if unset/zero. This isn't documented in package net.
cc @bradfitz
The text was updated successfully, but these errors were encountered: