rpc: fix flaky TestTracingHTTPTimeout (#35172)

`TestTracingHTTPTimeout` still flakes in CI after #35101, failing at the
POST:

    --- FAIL: TestTracingHTTPTimeout (0.26s)
        tracing_test.go:633: request: Post "http://127.0.0.1:43497": EOF

The test sets a short server `WriteTimeout` and posts a blocking call.
`ContextRequestTimeout` leaves a fixed 100ms for the server to write its
timeout response before the HTTP write deadline cuts the connection.

I can't repro it locally, but my theory is that under load that write
can miss the window, so the connection is dropped and the client POST
returns `EOF`, failing the test before it inspects the span. This is the
only test exposed to it because it is the only one that configures a
`WriteTimeout`.

The EOF is benign: the server sets the timeout error on the SERVER span
before attempting the write, independent of whether the client receives
the response. Since that span status is all the test asserts,
`tryPostJSONRPC` tolerates the transport error instead of failing on it.
This commit is contained in:
Jonny Rhea 2026-06-16 07:46:34 -05:00 committed by GitHub
parent 7d74166d3d
commit a326298f51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -346,17 +346,27 @@ func TestTracingSubscribeUnsubscribe(t *testing.T) {
// like notifications (no "id" field).
func postJSONRPC(t *testing.T, url, body string) {
t.Helper()
if err := tryPostJSONRPC(url, body); err != nil {
t.Fatalf("request: %v", err)
}
}
// tryPostJSONRPC is like postJSONRPC but returns the transport error instead of
// failing the test. The write-timeout test uses this because the HTTP
// WriteTimeout can drop the connection before the response is flushed.
func tryPostJSONRPC(url, body string) error {
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(body))
if err != nil {
t.Fatalf("new request: %v", err)
return err
}
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("request: %v", err)
return err
}
_, _ = io.Copy(io.Discard, resp.Body)
resp.Body.Close()
return nil
}
// TestTracingHTTPNotification verifies that a JSON-RPC notification emits the
@ -630,7 +640,12 @@ func TestTracingHTTPTimeout(t *testing.T) {
// test_block waits on ctx.Done() and returns an error. The internal
// timer cancels ctx, so test_block unblocks shortly after the timeout
// response goes out.
postJSONRPC(t, httpsrv.URL, `{"jsonrpc":"2.0","id":1,"method":"test_block"}`)
//
// Ignore the client-side result. Under load the HTTP WriteTimeout can
// drop the connection before the timeout response is flushed, which the
// client sees as EOF. The server still records the timeout on its span,
// which is what we assert below.
_ = tryPostJSONRPC(httpsrv.URL, `{"jsonrpc":"2.0","id":1,"method":"test_block"}`)
// Wait for the in-flight request to finish so the deferred spanEnd fires
// before GetSpans is called.