Skip to content

Fix the two Windows race-job flakes: pipe listener hang and QUIC port collision - #36

Merged
xeri merged 2 commits into
masterfrom
fix/windows-race-flakes
Nov 10, 2026
Merged

xeri merged 2 commits into
masterfrom
fix/windows-race-flakes

Conversation

@xeri

@xeri xeri commented Nov 10, 2026

Copy link
Copy Markdown
Owner

The race job on #35 failed on the same commit that had just passed. Two unrelated flakes, both on the Windows runner:

TestPipeSecondServerRejected hung until the 10m test timeout. The goroutine dump shows ipc.Serve waiting on go-winio's win32PipeListener.Close, which waits on a doneCh that listenerRoutine never closes. In v0.6.2, if Close lands while an Accept is pending, ConnectNamedPipe can race the handle close and return something other than ErrFileClosed. The listener then counts itself as still open. go-winio v0.6.4 fixes exactly this path: listener closure is authoritative there. Its ErrPipeListenerClosed is now a deprecated alias of net.ErrClosed, so isListenerClosed matches net.ErrClosed directly, as the unix side already does. v0.6.4 needs Go 1.26, which is why this PR is stacked on #35.

TestQUICRoundTrip / TestQUICMultiplexesPlayers timed out with listen udp 127.0.0.1:N: ... forbidden by its access permissions (WSAEACCES). The harness starts the gateway on an ephemeral TCP port, and the gateway binds UDP on the same number; on Windows that UDP port can be reserved or held exclusively. The gateway then serves TCP only, by design, so the QUIC tests can't pass. The same failure hit a dependabot PR's race job in August. The new Gateway.QUICAddr() reports the bound UDP address, or nil when QUIC is off or its bind failed. The harness's startGateway retries on a fresh port while it is nil. No product behaviour changes.

New versions: go-winio v0.6.4 (2026-10-13), x/sys v0.49.0 (2026-10-06, winio's minimum). Both are outside the 7-day cooldown.

Verified:

  • go test -short ./... green on Linux.
  • Retry path: a throwaway test (not committed) held the UDP port. QUICAddr() was nil, the harness shut each gateway down cleanly (goleak quiet), retried, then failed with its message. With the port freed, QUIC bound.
  • The winio fix only shows on Windows, so this PR's race job is the real check.

Merging this into fix/security-workflow puts both fixes on #35, so #35's next CI run includes them.

xeri added 2 commits November 10, 2026 20:36
v0.6.2's win32PipeListener.Close could wait forever: when Close lands while
an Accept is pending, ConnectNamedPipe can race the handle close and report
something other than ErrFileClosed (e.g. ERROR_NO_DATA). listenerRoutine
then treats the listener as still open, never closes doneCh, and Close
blocks on it. ipc.Serve waits for that Close before returning, so
TestPipeSecondServerRejected hung the race job until the 10m test timeout.
v0.6.4 makes listener closure authoritative on that path.

Its ErrPipeListenerClosed is now a deprecated alias of net.ErrClosed, so
isListenerClosed matches net.ErrClosed directly, like the unix side.
x/sys v0.49.0 comes along as winio's minimum.
The harness starts the gateway on an ephemeral TCP control port, and the
gateway binds UDP on the same number for QUIC. Nothing makes that number
free for UDP: Windows runners reserve UDP ranges and system services hold
UDP ports exclusively, so the bind sporadically fails with WSAEACCES. The
gateway then serves TCP only, as designed, and TestQUICRoundTrip and
TestQUICMultiplexesPlayers wait out their 10s deadline on a tunnel that
can never come up. It failed the race job on a dependabot PR in August
and again on #35.

Gateway.QUICAddr reports the bound UDP address (nil when QUIC is off or
its bind failed), and startGateway retries on a fresh port while it is
nil, so every harness with QUIC enabled really has it.
Base automatically changed from fix/security-workflow to master November 10, 2026 07:45
@xeri
xeri merged commit 876db05 into master Nov 10, 2026
23 checks passed
@xeri
xeri deleted the fix/windows-race-flakes branch November 10, 2026 07:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant