joule-moq-relay: the loop-of-relays test starts again on new ports when one it chose was taken #652

Merged
dcharlot merged 1 commit from test/relay-loop-port-race into main 2026-11-05 15:12:22 -05:00
Owner

a_loop_of_relays (joule-moq-relay tests/cascade.rs) failed on the linux-arm64 leg of #640 with the relay starts: "binding 127.0.0.1:34891: Address already in use (os error 98)". #640 changes no code here.

Why. The test's three relays each dial the next, so all three ports are chosen with free_port() before any relay listens. free_port() binds port 0, reads the port and lets it go. Another test running at the same time can bind that port in between, and the relay's start is then refused.

The fix. A start refused for a port in use is tried again on three new ports, at most five times. The relays already started are shut down first. Any other refusal still fails the test, and what the test holds of the loop is unchanged:

  • B and C hold A's namespace through the right paths;
  • it never comes back to A;
  • a viewer on C reaches A's publisher;
  • a request around the loop is refused with relay_loop at the relay that would close it.

Verified on a Linux build host:

  • The retry path runs. A scratch change, not committed, made the first port handed out one a listener keeps. The first start was refused, the test tried again on new ports and passed.
  • The cascade tests pass. All 12 passed, three runs in a row.
  • No new findings. clippy finds nothing in tests/cascade.rs.

🤖 Generated with Claude Code

`a_loop_of_relays` (joule-moq-relay `tests/cascade.rs`) failed on the linux-arm64 leg of #640 with `the relay starts: "binding 127.0.0.1:34891: Address already in use (os error 98)"`. #640 changes no code here. **Why.** The test's three relays each dial the next, so all three ports are chosen with `free_port()` before any relay listens. `free_port()` binds port 0, reads the port and lets it go. Another test running at the same time can bind that port in between, and the relay's start is then refused. **The fix.** A start refused for a port in use is tried again on three new ports, at most five times. The relays already started are shut down first. Any other refusal still fails the test, and what the test holds of the loop is unchanged: - B and C hold A's namespace through the right paths; - it never comes back to A; - a viewer on C reaches A's publisher; - a request around the loop is refused with `relay_loop` at the relay that would close it. **Verified on a Linux build host:** - **The retry path runs.** A scratch change, not committed, made the first port handed out one a listener keeps. The first start was refused, the test tried again on new ports and passed. - **The cascade tests pass.** All 12 passed, three runs in a row. - **No new findings.** clippy finds nothing in `tests/cascade.rs`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
joule-moq-relay: the loop-of-relays test starts again on new ports when one it chose was taken
All checks were successful
joule-moq-remote host agent / joule-moq-remote · does this change touch it (pull_request) Successful in 14s
joule-moq-room room service / joule-moq-room · does this change touch it (pull_request) Successful in 10s
joule-moq-web browser client / joule-moq-web · does this change touch it (pull_request) Successful in 10s
wai-app and Create / wai-app · does this change touch it (pull_request) Successful in 8s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 20s
WAI examples / WAI examples · does this change touch them (pull_request) Successful in 8s
WAI Studio / does this change touch it (pull_request) Successful in 8s
wai-fleet service / does this change touch it (pull_request) Successful in 23s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 3m38s
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (pull_request) Successful in 35s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (pull_request) Successful in 51s
wai-fleet service / service · linux (pull_request) Successful in 5m32s
WAI examples / WAI examples · portable · linux (pull_request) Successful in 8m59s
WAI Studio / Studio in WebKit · linux (pull_request) Successful in 11m5s
joule-code conformance gate / joule-moq-relay, its own energy on a counter (macos) (pull_request) Successful in 37s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (pull_request) Successful in 54s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m35s
wai-fleet service / service · macos (pull_request) Successful in 38s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (pull_request) Successful in 6m58s
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (pull_request) Successful in 13m23s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 10m18s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 17m54s
joule-code conformance gate / joule-moq-relay, every target (pull_request) Successful in 3m2s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m57s
joule-code conformance gate / joule-moq-ingest, every target (pull_request) Successful in 5m46s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 1m13s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 6m9s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 6m46s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 6m18s
7d1be82417
The three relays of a_loop_of_relays each dial the next, so their ports are chosen before any of
them listens, and another test can bind one in between: CI's linux-arm64 leg refused a start
with "Address already in use" (#640). A start refused for a port in use is now tried again on
three new ports, at most five times; any other refusal fails the test, and what the test holds
of the loop is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!652
No description provided.