mirror of
https://github.com/hanzoai/gateway.git
synced 2026-10-30 15:04:44 +00:00
Since the HIP-0110 ZAP-relay rearchitecture, cmd/gateway/main's
dialBackends eagerly dialed cloud:9090 / base:9091 at startup and
os.Exit(1)'d on any failure. When those backends are not deployed (the
steady state in prod), every gateway image past v2.14.1 crashlooped —
freezing the gateway on v2.14.1 and blocking the merged CORS fix and the
billing gate. HTTP serving (what api.hanzo.ai actually needs) worked fine.
Decomplect boot from backend reachability:
- startNode (was dialBackends) only starts the ZAP node. The single
fatal case left is a genuine local error — failure to bind the
ephemeral port. No dialing at startup.
- peerResolver (new, peer_resolver.go) lazily resolves a backend
address to its handshake-learned peerID, dialing on first use with
single-flight, caching once connected. ConnectDirectID is idempotent,
so a healthy backend is dialed exactly once and ZAP is unchanged.
- NewLazyPicker best-effort warms both backends (failure -> WARN, not
fatal) and returns the forward.PeerPicker. A dead backend makes the
picker return "" -> node.Call yields a per-request "peer not found"
error that forward.Relay surfaces as an HTTP error, never a crash.
The dial is retried on the next matching request (heals with no
restart once the backend appears).
- isBasePath is the single definition of the /v1/base/* split, shared
by the static pickPeer (tests) and the lazy picker (prod).
- RelayDeps.Pick lets main pass the lazy picker; nil falls back to the
static pickPeer for the pre-existing e2e test.
Tests (peer_resolver_test.go): boot succeeds with backends absent (no
hang/crash), healthz still serves 200, picker returns "" for dead
backends, ZAP routes+caches correctly when backends exist, and recovers
when a backend comes up. All pass under -race.