-
Notifications
You must be signed in to change notification settings - Fork 18k
x/net/http2: Long running http2 requests are closed immediately on server.Shutdown #29764
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
Comments
Further observation: There is a state to represent hijacked connections, but it is not applied to connections hijacked by the http2 library. |
More digging: h2_bundle has a method to set connection state to active when there is at least one active stream but it only calls sc.hc.ConnState which is just an optional hook and doesn't update the state of the connection in http/server. Keeping a reference to the http diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index 676eebdfdf..4e1a87ee76 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -3913,6 +3913,12 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
pushEnabled: true,
}
+ for hc := range opts.baseConfig().activeConn {
+ if hc.rwc == c {
+ sc.hconn = hc
+ }
+ }
+
s.state.registerConn(sc)
defer s.state.unregisterConn(sc)
@@ -4018,6 +4024,7 @@ type http2serverConn struct {
srv *http2Server
hs *Server
conn net.Conn
+ hconn *conn
bw *http2bufferedWriter // writing to conn
handler Handler
baseCtx context.Context
@@ -4159,7 +4166,10 @@ func (sc *http2serverConn) state(streamID uint32) (http2streamState, *http2strea
// Note that the net/http package does StateNew and StateClosed for us.
// There is currently no plan for StateHijacked or hijacking HTTP/2 connections.
func (sc *http2serverConn) setConnState(state ConnState) {
- if sc.hs.ConnState != nil {
+ if sc.hconn != nil {
+ sc.hconn.setState(sc.hconn.rwc, state)
+ } else if sc.hs.ConnState != nil {
+ // If we setState on the http connection above, it calls ConnState for us
sc.hs.ConnState(sc.conn, state)
}
}
|
The state of HTTP/2 connections is currently never set to StateActive, causing them to be closed immediately on server.Shutdown if they are at least 5 seconds old. This change modifies the Shutdown tests so that the h2 version fails with the existing implementation, and introduces a method on the http Server to set the state from within the http2 bundle/package. This is a proof of concept and illustration of the issue. The new exported method on the Server type is probably a Very Bad Idea and a naive implementation to boot. I'd love suggestions for a better solution. Fixes golang#29764
Change https://golang.org/cl/158840 mentions this issue: |
CC @bradfitz @tombergan for http2. |
Best effort workaround: github.com/callum-oakley/polite-http-server. |
Looks like duplicate of #39776 fixed by https://go-review.googlesource.com/c/go/+/240278 The provided example now waits for full countdown. |
Duplicate of #39776 |
What version of Go are you using (
go version
)?I can reproduce this on
go version go1.11.4 darwin/amd64
but not ongo version go1.10.7 darwin/amd64
.Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
This snippet starts a server that responds to every request by counting for 10 seconds. On SIGINT we initiate graceful shutdown of the server, waiting for all connections to be idle. This should block shutdown as long as there are in flight requests.
create
cert.pem
andkey.pem
with something likethen run
Make an HTTP/2 request, with curl built with HTTP/2 support, nghttp, etc and then send SIGINT to the go process.
What did you expect to see?
Shutdown blocks until all in flight requests have finished counting to 10.
What did you see instead?
For HTTP/1.1 connections Shutdown does block until all in flight requests have finished counting to 10, but HTTP/2 connections older than 5s are closed immediately (younger connections are closed as soon as they reach 5s old).
Sample output sending SIGINT 5s in to a HTTP/1.1 request
Sample output sending SIGINT 5s in to a HTTP/2 request
Observations from digging around in the code
This seems to happen because HTTP/2 connections remain in
StateNew
even though data is being written to them. Then when they are 5s oldcloseIdleConns
(called by Shutdown) considers them idle and closes them. This behaviour was introduced here.The text was updated successfully, but these errors were encountered: