Closed as not planned
Description
Go version
1.21
Output of go env
in your module/workspace:
GO111MODULE=''
GOARCH='arm64'
GOBIN=''
GOCACHE='/Users/khushijain/Library/Caches/go-build'
GOENV='/Users/khushijain/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMODCACHE='/Users/khushijain/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPATH='/Users/khushijain/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.23.1/libexec'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.23.1/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.23.1'
GODEBUG=''
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/khushijain/Library/Application Support/go/telemetry'
GCCGO='gccgo'
GOARM64='v8.0'
AR='ar'
CC='cc'
CXX='c++'
CGO_ENABLED='1'
GOMOD='/Users/khushijain/Documents/elastic-agent-libs/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/cv/_38x0gd965v0156jwblb9x6h0000gn/T/go-build243205887=/tmp/go-build -gno-record-gcc-switches -fno-common'
What did you do?
If you set IdleConnectionTImeout
timeout on http.Transport
to 2s. And send two separate requests with 5 seconds delay between them with custom logging dialer which logs an error received during read
and write
operations on net.Conn
We receive a use of closed connection
error on sending the second request. The error is from the read
method on net.Conn
. It seems like it was trying to reuse the first connection which was closed due to timeout. We expected Go to internally handle not reusing old connections
How to reproduce
// Set up a test HTTP server
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `{"status": "ok"}`)
}))
defer server.Close()
logger := logp.NewLogger("test")
// Set IdleConnTimeout to 2 seconds and a custom dialer
transport := &http.Transport{
IdleConnTimeout: 2 * time.Second,
// uses our implementation of custom dialer
DialContext: LoggingDialer(NetDialer(10*time.Second), logger).DialContext,
}
client := &http.Client{
Transport: transport,
}
// First request to the test server
resp, err := client.Get(server.URL) //nolint:noctx // It is a test
require.NoError(t, err, "first request failed")
_, _ = io.ReadAll(resp.Body)
resp.Body.Close()
// Wait for a duration longer than IdleConnTimeout
waitTime := 6 * time.Second
time.Sleep(waitTime)
// Second request to the test server after idle timeout
resp, err = client.Get(server.URL) //nolint:noctx // It is a test
require.NoError(t, err, "second request failed")
_, _ = io.ReadAll(resp.Body)
resp.Body.Close()
What did you see happen?
use of closed network connection
What did you expect to see?
We expected a new connection would be used to read from the buffer. Instead it reuses an old connection that has already been closed due to timeout