Skip to content

fix(e2e): stabilize listen-port races and reload polls - #725

Merged
stackia merged 12 commits into
mainfrom
cursor/e2e-port-stability-93e5
Aug 22, 2026
Merged

fix(e2e): stabilize listen-port races and reload polls#725
stackia merged 12 commits into
mainfrom
cursor/e2e-port-stability-93e5

Conversation

@stackia

@stackia stackia commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

Recent E2E CI failures (especially macOS) were not product regressions. The dominant flake was:

RuntimeError: rtp2httpd did not start on port 49234

Failed ports (49220, 49234, 49334, 50597, 51059) all sit in the macOS ephemeral range (49152-65535). find_free_port() used bind(0) and immediately closed the socket. Under pytest-xdist, another worker's client connect() could take that port as a source port before rtp2httpd bound 0.0.0.0/::.

Changes

  • Allocate TCP/UDP listen ports from a per-xdist-worker range below typical ephemeral windows (14000-32399), with a short reuse cooldown.
  • Probe 0.0.0.0 (not just 127.0.0.1) so we do not hand out a port that rtp2httpd cannot bind on the wildcard.
  • R2HProcess.start() always captures logs, fail-fasts if the process exits, and includes the log + exit code in the error.
  • Reload polls in test_pages.py treat ConnectionRefusedError as "not ready yet".
  • Fail-fast helper test uses a portable /bin/sh script (/bin/false is missing on FreeBSD).

Stability gate

10/10 consecutive E2E Tests workflow runs passed (ubuntu + macos + freebsd on each):

  1. https://github.com/stackia/rtp2httpd/actions/runs/32570404984
  2. https://github.com/stackia/rtp2httpd/actions/runs/32570768645
  3. https://github.com/stackia/rtp2httpd/actions/runs/32571085377
  4. https://github.com/stackia/rtp2httpd/actions/runs/32571294466
  5. https://github.com/stackia/rtp2httpd/actions/runs/32571621032
  6. https://github.com/stackia/rtp2httpd/actions/runs/32571964530
  7. https://github.com/stackia/rtp2httpd/actions/runs/32572322088
  8. https://github.com/stackia/rtp2httpd/actions/runs/32572679560
  9. https://github.com/stackia/rtp2httpd/actions/runs/32573038234
  10. https://github.com/stackia/rtp2httpd/actions/runs/32573279775

The preceding run on bf78c19 failed only because FreeBSD has no /bin/false; that helper test was fixed before this 10-run streak.

Test plan

  • uv run ruff check e2e
  • ./scripts/run-e2e.sh --co
  • ./scripts/run-e2e.sh -p 1 test_port_helpers.py
  • ./scripts/run-e2e.sh — 576 passed locally
  • GitHub Actions E2E matrix x10 on this PR — all passed
Open in Web Open in Cursor 

cursoragent and others added 2 commits August 22, 2026 11:25
CI flakes on macOS were "rtp2httpd did not start on port 49xxx" because
find_free_port() used bind(0), which returns ports from the kernel
ephemeral pool. Parallel xdist workers then reused those ports as client
source ports before rtp2httpd could bind.

Take listen ports from a per-worker range below 32768, probe the IPv4
wildcard, and fail-fast in R2HProcess.start() with process logs when
startup dies or times out.

Co-authored-by: Stackie Jia <jsq2627@gmail.com>
SIGHUP restarts workers and briefly drops the listen socket. Polling
http_get() could raise ConnectionRefusedError on FreeBSD instead of
returning a non-200 status, aborting the retry loop.

Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Comment thread e2e/helpers/ports.py
sockets.append(sock)
if family == socket.AF_INET6:
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
sock.bind((bind_host, port))
Comment thread e2e/helpers/ports.py
def _can_bind_udp(port: int) -> bool:
try:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.bind(("", port))
Comment thread e2e/test_port_helpers.py
def test_find_free_port_is_bindable_on_wildcard():
port = find_free_port()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(("0.0.0.0", port))
Comment thread e2e/test_port_helpers.py
port = find_free_udp_port()
assert start <= port < end
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
sock.bind(("", port))
Comment thread e2e/test_port_helpers.py Fixed
Comment thread e2e/test_port_helpers.py Fixed
@github-actions

github-actions Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Documentation preview

The documentation preview has been deployed for this pull request.

@stackia
stackia marked this pull request as ready for review August 22, 2026 11:27
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

FreeBSD CI has no /bin/false, so the new helper test aborted in Popen
before it could assert the exit-code path. Use a chmod +x /bin/sh
script instead, and surface spawn OSError from R2HProcess.start().

Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Comment thread e2e/test_port_helpers.py
assert odd == even + 1
assert start <= even < odd < end
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s1, socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s2:
s1.bind(("", even))
Comment thread e2e/test_port_helpers.py
assert start <= even < odd < end
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s1, socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s2:
s1.bind(("", even))
s2.bind(("", odd))
cursoragent and others added 9 commits August 22, 2026 11:37
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
Co-authored-by: Stackie Jia <jsq2627@gmail.com>
@stackia
stackia merged commit 86bf485 into main Aug 22, 2026
11 checks passed
@stackia
stackia deleted the cursor/e2e-port-stability-93e5 branch August 22, 2026 12:47
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.

3 participants