Skip to content

Replace the home-relay watchdog with in-place relay failover - #6

Merged
andrewchen5678 merged 3 commits into
mainfrom
relay-failover
Sep 5, 2026
Merged

andrewchen5678 merged 3 commits into
mainfrom
relay-failover

Conversation

@andrewchen5678

Copy link
Copy Markdown
Contributor

Summary

  • Watchdog and rebuild removed. The 60 s nudge (Endpoint::network_change()) never did anything on a stable host: netmon re-reads the interfaces, finds no change, and nothing reaches the relay actor. The 180 s rebuild dropped every connection. relay_watchdog, rebuild_endpoint, EndpointFactory and RebuildableEndpoint are gone.
  • In-place failover (relay_failover::fail_over_home_relay): after 60 s without a connected home relay, remove the wedged relay from the endpoint's relay map. The map is a shared handle, so the removal is seen by net_report and the relay actor; a relay-map change forces a full report; the report can only prefer a relay still in the map; the endpoint homes there. Identity, direct paths and established connections are untouched. The removed relay is probed every 90 s and re-inserted once connectable, so a relay that answers HTTP but refuses relay connections cannot be re-selected in a loop. With no home relay selected at all, the first relay is re-inserted unchanged to force a report.
  • Custom relays must number at least two (relay::MIN_CUSTOM_RELAYS); one relay leaves nothing to fail over to. The default relay map is unaffected.
  • Startup probe fails only when no relay is reachable, warning per unreachable relay. With two relays mandatory, requiring every relay at startup would stop clients from restarting during a relay outage, which is the failover case.
  • Version 0.0.7 (v0.0.4–v0.0.6 exist on superseded branches).

Design and iroh 1.1.0 analysis: flexaccessdev/iroh-common-architecture#relay-failover (relay-failover.md). First consumer: flexaccessdev/tunnel-rs relay-failover, whose fully offline e2e suite exercises the failover with a relay that answers /ping but refuses relay connections.

Test plan

  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo test --all-features (22 tests; six paused-clock tests for the failover loop)
  • tunnel-rs test-scripts/run_relay_failover_e2e.sh, all ten scenarios, twice
  • tunnel-rs test-scripts/run_e2e.sh against two local dev relays, relay-only and normal

🤖 Generated with Claude Code

https://claude.ai/code/session_01HnozJMiCj3v5Xfdb9gB5S8

The watchdog's two steps were a nudge that did nothing on a stable host
(`network_change()` only asks netmon to re-read interfaces, which reports
"no change") and a rebuild that dropped every connection. Both are gone.

`relay_failover::fail_over_home_relay` watches the home-relay status and,
after 60 s without a connected home relay, removes the wedged relay from
the endpoint's relay map. The relay-map change forces a full net report,
which can only prefer a relay still in the map, so the endpoint homes on
another configured relay while its identity, direct paths and established
connections stay untouched. The removed relay is probed every 90 s and put
back once it is connectable again, so a relay that answers HTTP but refuses
relay connections cannot be re-selected and fail again in a loop.

Custom relay sets must now hold at least two distinct relays, since one
relay leaves nothing to fail over to. The startup probe fails only when no
relay is reachable and warns per unreachable relay, so a client restarting
during a relay outage still starts on the surviving relay.

`rebuild_endpoint`, `EndpointFactory` and `RebuildableEndpoint` are removed
with the rebuild step.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HnozJMiCj3v5Xfdb9gB5S8
Andrew Chen and others added 2 commits September 4, 2026 20:37
The custom relay count is taken after deduplication, so say "at least
two distinct relays" everywhere the minimum is described; listing the
same relay twice is not a valid two-relay configuration.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HnozJMiCj3v5Xfdb9gB5S8
Review fixes in relay_failover:

- The restore wait was a nested loop: while a removed relay stayed
  unconnectable, a newly wedged home relay was reported but never failed
  over. The loop is now a single select over the report timer, the
  failover timer, the per-relay restore deadlines and the status watcher,
  tracking every removed relay with its own next probe time (each still
  spaced RELAY_RESTORE_INTERVAL apart so a returning relay gets a fresh
  actor). The last relay left in the map is never removed; the endpoint
  is nudged instead, and a nudge re-inserts only a relay that is still in
  the map, never a removed one.
- restore() reports success only after insert_relay ran; a connectable
  relay missing from the configured map is logged and left out.
- fail_over_home_relay no longer indexes urls[0]: an empty custom relay
  set (constructible from outside the crate) stays pending instead of
  panicking.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HnozJMiCj3v5Xfdb9gB5S8
@andrewchen5678
andrewchen5678 merged commit ac8e12a into main Sep 5, 2026
3 checks passed
@andrewchen5678
andrewchen5678 deleted the relay-failover branch September 5, 2026 03:58
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