net/http/internal/http2: let the server's serve goroutine exit when idle Implement the TODO from 2014 at the top of server.go: a server connection with nothing to do used to pin a goroutine blocked in the serve loop (reached through net/http's conn.serve and ServeConn) in addition to the readFrames goroutine; now it pins only readFrames. When the serve loop has nothing runnable (nothing being written, unflushed, or poppable on the write side, and no shutdown in progress), the serve goroutine parks: it simply exits. Every sender into the serve loop's channels first calls beginServeSend, which counts in-flight sends and revives a parked loop on a new goroutine, so a frame from the peer, a handler write or body read, a timer firing, or a graceful shutdown request wakes the connection back up. Open streams and running handlers don't prevent parking, since the handler-side paths into the serve loop (response writes, body reads, stream deadline timers, pushes) all go through beginServeSend too. This helps SSE/long-poll-style servers: a connection whose handler is parked mid-long-poll for hours pins only the readFrames and handler goroutines, and the handler's next Write or Flush revives the loop. With open streams, the write scheduler can still hold DATA frames blocked on flow control; that's fine to park on, because only an incoming WINDOW_UPDATE or SETTINGS frame can unblock them, and incoming frames revive the loop. The serve loop's teardown became explicit rather than deferred, and it takes over the cleanup that ServeConn's callers used to do after it returned (closing the connection, unregistering it, and running net/http's StateClosed hook), signaled through the new ServeConnOpts.OnClose hook. Callers that don't set OnClose keep the old blocking ServeConn semantics and never park. Parking happens between the frames of an active request, so the park/resume cycle runs on hot paths. Spawning the resume goroutine with a pre-allocated method-value closure keeps it allocation-free: BenchmarkClientServer/h2 reports the same 68 allocs/op as before, with ns/op unchanged within noise. As a temporary safety measure, the GODEBUG=http2serveparking=0 setting disables parking, restoring the old behavior of keeping a goroutine parked for the lifetime of each connection. The setting is undocumented (#-prefixed), so it is not listed in doc/godebug.md or runtime/metrics. This is the server-side counterpart of CL 810780, which let the Transport's request-write goroutine exit early for the same reason: for servers with many mostly-idle connections, a parked goroutine and its stack per connection add up. Updates #80735 Updates #81524 Change-Id: I4a9fd4e2ce7a7a4e0f84179e54a9cc97d1a62ad5 Reviewed-on: https://go-review.googlesource.com/c/go/+/831084 Reviewed-by: Nicholas Husin <husin@google.com> Reviewed-by: Nicholas Husin <nsh@golang.org> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Damien Neil <dneil@google.com>
Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
Gopher image by Renee French, licensed under Creative Commons 4.0 Attribution license.
Our canonical Git repository is located at https://go.googlesource.com/go. There is a mirror of the repository at https://github.com/golang/go.
Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file.
Official binary distributions are available at https://go.dev/dl/.
After downloading a binary release, visit https://go.dev/doc/install for installation instructions.
If a binary distribution is not available for your combination of operating system and architecture, visit https://go.dev/doc/install/source for source installation instructions.
Go is the work of thousands of contributors. We appreciate your help!
To contribute, please read the contribution guidelines at https://go.dev/doc/contribute.
Note that the Go project uses the issue tracker for bug reports and proposals only. See https://go.dev/wiki/Questions for a list of places to ask questions about the Go language.