Go 1.23에서 keep-alive 때문에 httptest.Server.Close가 멈추는 일이 있을 수 있나요? go test -timeout 5s ./...를 돌리는데 새 테스트가 통과도 실패도 안 하고 타임아웃까지 그냥 있어요. 그러다 panic: test timed out after 5s랑 goroutine 덤프가 나오는데, quickfix 어디에도 assertion 텍스트가 없어요.
덤프를 보면 테스트 goroutine은 httptest.(*Server).Close에 있고, 제가 defer로 건 srv.Close()에서 호출된 sync.WaitGroup.Wait에서 기다리고 있어요. 핸들러 goroutine은 chan receive에 있고, 세 번째는 persistConn.roundTrip 안의 select에 있어요.
-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?