Skip to content

Bind without relays that fail the startup probe; test failover behind a direct path - #8

Merged
andrewchen5678 merged 4 commits into
mainfrom
e2e-mixed-mode-failover
Sep 5, 2026
Merged

andrewchen5678 merged 4 commits into
mainfrom
e2e-mixed-mode-failover

Conversation

@andrewchen5678

Copy link
Copy Markdown
Contributor

Summary

  • Fix: a process starting while its latency-preferred relay answers probes but refuses relay connections never came online (iroh's online() waits only for a connected home relay, and iroh keeps choosing the wedged relay by latency). This is what the old watchdog restarts were working around. The startup probe now reports the relays that fail, the endpoint is bound without them, and fail_over_home_relay restore-probes them every 90 s and puts them back once connectable. iroh DNS discovery was verified (source + empirical) not to fix this.
  • API change (no backward compatibility): create_endpoint returns CreatedEndpoint { endpoint, relays_left_out }; fail_over_home_relay takes relays_left_out as a third argument.
  • e2e: new phase D in run_relay_failover.sh exercises the failover behind a live direct connection (mixed mode, built without mdns): the held client prints every connection path with its selected flag and RTT (like flextunnel's connection-path status), the server is asserted to re-home, a fresh relay-only client's path shows the new home relay, and a client redialing with the same two relays during the outage comes online through the new home relay and goes direct again (D2, the scenario that exposed the bug).
  • Version bump to 0.0.8.

Test plan

  • cargo test and cargo clippy --all-targets -- -D warnings, with and without --all-features
  • ./e2e/run_e2e.sh --local-relays and --local-relays --relay-only
  • ./e2e/run_relay_failover.sh 13/13 PASS (D2 fails without the fix)

🤖 Generated with Claude Code

https://claude.ai/code/session_01RZhxxjP2TA93PHNr6p1BU8

Andrew Chen and others added 4 commits September 5, 2026 08:14
The relay failover suite ran every scenario relay-only, so nothing showed
the failover acting while a direct path carried traffic, which is the
shape of the original incident (LAN clients kept working and masked it).

The harness now echoes every further stream on an authenticated
connection, and a client can hold its connection open (--hold-secs),
echoing on a fresh stream every few seconds and logging every path of
the connection with the selected one marked, like flextunnel's
connection-path status. It refuses mixed mode when built with the mdns
feature: on one host mDNS would hand the client the server's address and
the relays would never be exercised.

Phase D, server and held client with direct paths allowed:
  D0  the held connection's paths are relay1 + direct, direct selected
  D1  relay1 wedges; the failover still removes it and homes the server
      on relay2 while the held client keeps echoing over its direct path;
      the held connection ends up direct-only (iroh does not add a peer's
      new home relay to an established connection); a fresh relay-only
      client's path shows relay2
  D2  a client with the same two-relay configuration redials during the
      outage: it must come online, connect via relay2, and go direct again

D2 fails today: the redialing client's own net report prefers the wedged
relay (it answers probes fastest), its relay connection to it never
completes, iroh's online() needs a connected home relay, and
create_endpoint gives up after 10 s. The server's failover cannot help a
client that never comes online.

Every scenario that expects a specific home relay now asserts the relay
URL on the client's connection path, not just that an echo went through.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZhxxjP2TA93PHNr6p1BU8
A process starting while its preferred relay answers probes but refuses
relay connections could never come online: iroh picks the home relay by
probe latency, so it kept choosing the wedged relay, the relay
connection failed forever, online() stayed pending, and create_endpoint
gave up after 10 s. Every client restarting during such an outage failed
to start although the other relay worked and the server had already
failed over to it. This is what the watchdog restarts were working
around, and DNS discovery cannot help: online() only watches the home
relay status (verified with n0 DNS lookup and pkarr publishing enabled).

probe_custom_relays now returns the relays that did not come online, and
create_endpoint binds the endpoint with a relay map without them, so it
homes on a relay that works. It returns a CreatedEndpoint carrying the
relays left out; fail_over_home_relay takes them as already removed and
its restore probe puts each one back once it is connectable again.

The e2e scenario D2 (a client with the two-relay configuration redials
after the server re-homed, relay1 still wedged) now passes: the client
leaves relay1 out, connects via relay2, and moves onto a direct path.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZhxxjP2TA93PHNr6p1BU8
Consumers must now take `CreatedEndpoint` from `create_endpoint` and hand
its `relays_left_out` to `fail_over_home_relay`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RZhxxjP2TA93PHNr6p1BU8
@andrewchen5678
andrewchen5678 merged commit e718f5d into main Sep 5, 2026
4 checks passed
@andrewchen5678
andrewchen5678 deleted the e2e-mixed-mode-failover branch September 5, 2026 15:52
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