Возможно ли, что httptest.Server.Close виснет на Go 1.23 с keep-alive? Запускаю go test -timeout 5s ./..., и новый тест ни проходит, ни падает. Он просто висит до таймаута, потом я получаю panic: test timed out after 5s и дамп горутин, а текста assertion нет нигде, в quickfix тоже.
В дампе горутина теста находится в httptest.(*Server).Close, ждёт в sync.WaitGroup.Wait, вызвана из моего отложенного srv.Close(). Горутина хендлера в chan receive, а третья в select внутри persistConn.roundTrip.
-count=1, -race и DisableKeepAlives ничего не меняют. JSON-тест в том же файле проходит.
gate := make(chan struct{})
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
<-gate // gateway holds the ack
w.WriteHeader(http.StatusAccepted)
}))
defer srv.Close()
c := NewClient(srv.URL, log.New(io.Discard, "", 0))
errc := make(chan error, 1)
go func() { errc <- c.Send(context.Background(), testBatch()) }()
time.Sleep(100 * time.Millisecond)
if got := c.Pending(); got != 1 {
t.Fatalf("Pending() = %d while ack is held, want 1", got)
}
close(gate)
Почему здесь блокируется Close и куда делось моё сообщение об ошибке?
Переведено с английского·Показать оригиналIs it possible that httptest.Server.Close hangs on Go 1.23 with keep-alive? I run go test -timeout 5s ./... and the new test neither passes nor fails. It sits until the timeout, then I get panic: test timed out after 5s and the goroutine dump, and no assertion text anywhere in quickfix.
In the dump, the test goroutine is in httptest.(*Server).Close, waiting in sync.WaitGroup.Wait, called from my deferred srv.Close(). The handler goroutine is in chan receive, and a third is in select inside persistConn.roundTrip.
-count=1, -race and DisableKeepAlives change nothing. The JSON test in the same file passes.
gate := make(chan struct{})
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
<-gate // gateway holds the ack
w.WriteHeader(http.StatusAccepted)
}))
defer srv.Close()
c := NewClient(srv.URL, log.New(io.Discard, "", 0))
errc := make(chan error, 1)
go func() { errc <- c.Send(context.Background(), testBatch()) }()
time.Sleep(100 * time.Millisecond)
if got := c.Pending(); got != 1 {
t.Fatalf("Pending() = %d while ack is held, want 1", got)
}
close(gate)
Why would Close block here, and where did my failure message go?