-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Closed
Labels
FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.The path to resolution is known, but the work has not been done.
Milestone
Description
What version of Go are you using (go version
)?
$ go version go version go1.15.2 linux/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/hiroaki-m/.cache/go-build" GOENV="/home/hiroaki-m/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/home/hiroaki-m/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/hiroaki-m/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build121864325=/tmp/go-build -gno-record-gcc-switches"
What did you do?
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
)
type handler struct{}
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Length", "0")
}
func requestAndCancel(url string) {
for {
wait := make(chan struct{})
done := make(chan struct{})
ctx, cancel := context.WithCancel(context.Background())
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
go func() {
close(wait)
http.DefaultTransport.RoundTrip(req)
close(done)
}()
<-wait
cancel()
<-done
}
}
func main() {
ts := httptest.NewServer(&handler{})
defer ts.Close()
http.DefaultTransport.(*http.Transport).MaxConnsPerHost = 1
// request and cancel
for i := 0; i < 8; i++ {
go requestAndCancel(ts.URL)
}
// request only
for {
req, _ := http.NewRequest(http.MethodGet, ts.URL, nil)
if _, err := http.DefaultTransport.RoundTrip(req); err != nil {
fmt.Printf("An unexpected error has occurred: %#v\n", err)
break
}
}
}
I'm gussing that the keep-alived tcp connection is used simultaneously by multiple goroutine.
Early return to connection pool https://go.googlesource.com/go/+/refs/tags/go1.15.2/src/net/http/transport.go#2089
What did you expect to see?
No error response and loop infinity.
What did you see instead?
$ date -u; go run context_cancel_race.go ; date -u
Thu 24 Sep 2020 03:28:55 AM UTC
An unexpected error has occurred: &errors.errorString{s:"context canceled"}
Thu 24 Sep 2020 03:30:00 AM UTC
mmurasawa
Metadata
Metadata
Assignees
Labels
FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.The path to resolution is known, but the work has not been done.