Skip to content

Skip e2e port slots whose proxy ports cannot be bound - #112

Merged
arthurfiorette merged 2 commits into
mainfrom
fix/e2e-proxy-port-collision
Nov 1, 2026
Merged

arthurfiorette merged 2 commits into
mainfrom
fix/e2e-proxy-port-collision

Conversation

@arthurfiorette

@arthurfiorette arthurfiorette commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

with::with_runs_the_command_and_stops_the_daemon_it_spawned failed on main in run 41354847203 (e2e, macos-latest). Its daemon logged Port 26190 is in use by another process; using 8443, so DEVLANES_PUBLIC_URL_API carried 8443 and the script exited 90.

Cause

PortSlot::acquire always takes the lowest free slot, so a test usually gets the slot the previous test on its nextest thread just released. In that run slot 1 (base 26100) went to with_keeps_the_exit_code_and_stops_the_lane, which curls through the proxy on 26190, then to with_never_ready_service_skips_the_command, then to the failing test about 5 s later. Slot 0 was held by the update test the whole time.

The daemon binds its proxy ports without SO_REUSEADDR (crates/proxy/src/listener.rs, bind), which is deliberate on macOS. A connection to the proxy that the proxy closed first leaves 26190 in TIME_WAIT (30 s on macOS, 60 s on Linux), and until then that bind fails with AddrInUse, so the proxy falls back to 8443. Only the HTTPS port warned; 26191 (HTTP, which saw no traffic) bound fine. A live process holding the slot would have taken both ports.

The fallback is intended product behaviour, so the fix goes in the harness: before it hands out a slot, PortSlot::acquire now binds the slot's proxy ports on 127.0.0.1 and ::1 the way the daemon does, and moves on to the next slot if either is refused. Only AddrInUse and PermissionDenied count, so a host without IPv6 still works.

Verification

  • Reproduced on Linux (WSL) with a scratch test, not committed. It left one server-side TIME_WAIT on slot 0's 26090 and then started a lab. Before the fix the lab took slot 0 and the daemon logged Port 26090 is in use by another process; using 8443., the same warning as CI. With the fix the lab skipped slot 0 and the proxy bound 26190.
  • Linux (WSL): full cargo nextest run --profile e2e passed (54 including the scratch test, 4 skipped), and with::, update:: and proxy:: passed 8 times in a row. That run also had an update.rs fix that Export the lane's project as DEVLANES_LANE_PROJECT #109 has since made on main, so this PR no longer includes it.
  • Windows: full cargo nextest run --profile e2e passed (59 passed, 4 skipped).
  • cargo fmt --all --check and cargo clippy -p devlanes-e2e --all-targets --all-features -- -D warnings are clean.

I could not run macOS locally. On Linux, curl through the proxy closed with RST and left no TIME_WAIT in 300 tries, so I have not confirmed which side closed first on the macOS runner. The harness check covers any refusal on those ports either way.

No change file: this only changes tests.

Written by OpenCode / Claude Opus 5.5

@sampo-s-bot

sampo-s-bot Bot commented Nov 1, 2026

Copy link
Copy Markdown

⚠️ No changeset detected

No new .sampo/changesets/*.md files were detected in this PR. To add one:

  • run sampo add
  • follow the prompts to pick the affected packages and describe the change
  • commit the generated file to this pull request, and it will be detected automatically

If this PR isn't supposed to introduce any changes (e.g., documentation updates), you can ignore this message.

@mira-arthur

mira-arthur Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Mira PR Walkthrough

Fixes a flaky e2e failure on macOS where a recently released port slot still had its proxy HTTPS port in TIME_WAIT, causing the daemon to fall back to 8443. PortSlot::acquire now probes the slot's proxy ports on 127.0.0.1 and ::1 (mirroring the daemon's bind without SO_REUSEADDR) and skips slots where binding fails with AddrInUse or PermissionDenied. The change is confined to the e2e harness; product behavior is unchanged.

Confidence: 4/5   ◉◉◉◉○   Safe to merge
  • Test-only change with a well-reasoned root cause and a Linux/Windows reproduction, though the macOS fix itself couldn't be verified locally.

Blast Radius — 2 dependent repositories, 16 total references

devlanes-run/action — 4 references
devlanes-run/website — 12 references

2 files reviewed


Comment @mira-arthur help to get the list of available commands and usage tips.

A lab took the lowest free slot right after the previous lab in that slot released it. A connection that proxy closed first leaves its HTTPS port in TIME_WAIT, the daemon binds without SO_REUSEADDR, and the next lab's proxy fell back to 8443, failing with_runs_the_command_and_stops_the_daemon_it_spawned on macOS. The update tests also replaced the lab's user config, so their daemons ran on the default ports outside their slot.
@arthurfiorette
arthurfiorette force-pushed the fix/e2e-proxy-port-collision branch from 8503424 to c5ce8b9 Compare November 1, 2026 23:37
@arthurfiorette
arthurfiorette enabled auto-merge (squash) November 1, 2026 23:48
@arthurfiorette
arthurfiorette merged commit 360f22a into main Nov 1, 2026
14 checks passed
@arthurfiorette
arthurfiorette deleted the fix/e2e-proxy-port-collision branch November 1, 2026 23:54
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