Skip to content

test: TestBackloggedPeerIsClosed failed once under -race in CI (epoll/adaptive async-route, 2 of 4 responses) #1068

Closed

Description

@FumingPower3925

TestBackloggedPeerIsClosed (test/server/large_response_linux_test.go, from #761) failed once in CI and passed on the re-run of the same commit.

Needs: reproduce under -race -count=N on a loaded runner, then either widen the observable condition (wait for the queued bytes to drain instead of a grace) or fix the engine if the close really happens early.

Activity

  1. added this to the v1.6.0 milestone on Oct 18, 2026
  2. FumingPower3925 commented on Oct 25, 2026

    @FumingPower3925
    ContributorAuthor

    Status: the mechanism is found and a fix is in review (draft #1106, Refs only). Correcting the issue body: the "2 of 4" line in the log is adaptive's passing line; the real failure was a truncated first response (the response of an async route that ends its connection, cut at the byte count the first flush took).

    Mechanism: in the epoll serveAsync the dispatch goroutine stored asyncClosed BEFORE taking asyncInMu to clear asyncRun; drainDetachQueue could look in that gap, take it for an outside close of a running handler and call closeConn while the response's remainder was still queued, so the client read EOF at the bytes the socket buffers had taken. The same bug explains the TestStreamedResponseIsDelivered/*/async-route/close truncation (8 CI occurrences on 5 runs, offsets 2681685 / 2634069 / 2634119 of 8 MiB) that is only mentioned in #890: tracked here, no separate issue. io_uring has no such gap (its closing path hands the bytes to closeConn, which defers the close behind them).

    Evidence: failing-first test TestAsyncRouteCloseSendsTheQueuedRemainder1068 fails 20 of 20 with only the lock move reverted (at the CI byte counts) and passes 30 of 30 with the fix; natural rate on main with --cpus 2 plus busy loops 2 of 1500, 0 of 6000 after the fix (Fisher p = 0.04, supporting evidence only; the deterministic test is the proof). Two Opus reviews (correctness and concurrency; performance and statistics) found no blocker; a similar gap in abortAsyncHandler (a handler that panics past recovery) is being addressed in the same PR.

  3. FumingPower3925 commented on Oct 29, 2026

    @FumingPower3925
    ContributorAuthor

    Fixed by #1106 (merged 2026-10-25), verified by failing-first reproduction in the review of the flake lane: the fix reverted fails the regression test 20 of 20, the merged tree passes 20 of 20 (#1068 epoll async closing response truncation: product bug; #1107 and #1108: test bugs). No recurrence in the CI runs since the merge. Refs #1106.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions