Skip to content

fix(cli): retry registry requests and fall back to IPv4 - #47

Open
dennytosp wants to merge 1 commit into
rit3zh:mainfrom
dennytosp:fix/cli-registry-fetch-resilience
Open

fix(cli): retry registry requests and fall back to IPv4#47
dennytosp wants to merge 1 commit into
rit3zh:mainfrom
dennytosp:fix/cli-registry-fetch-resilience

Conversation

@dennytosp

Copy link
Copy Markdown

Fixes #39

Problem

npx reacticx list / reacticx add <component> fail on some networks with a raw undici error:

[TypeError: fetch failed] {
  [cause]: ConnectTimeoutError: Connect Timeout Error
      (attempted addresses: 2606:4700:310c::ac42:2ca8:443, timeout: 10000ms)
    code: 'UND_ERR_CONNECT_TIMEOUT'
}

Cause

getRegistry and getComponentCode each called fetch exactly once, with no timeout, no retry, and no error handling beyond response.ok. On a dual-stack network that advertises an AAAA record for the registry host but cannot actually route IPv6, the first connect hangs until undici gives up — and there is nothing to recover it. The reporter also had no way to raise the timeout, and the thrown error gave no hint about what to try.

Fix

Both requests now go through a fetchWithRetry helper that:

  • retries up to 3 times with an incremental backoff — fetch only rejects on transport-level failures (an HTTP error status resolves normally), so anything thrown is worth another attempt;
  • switches the DNS resolver to ipv4first after a connect-level failure (UND_ERR_CONNECT_TIMEOUT, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT), so a broken IPv6 route recovers on the next attempt. This is only applied as a fallback, so IPv6-only networks are unaffected;
  • applies an explicit 30s timeout, overridable with REACTICX_FETCH_TIMEOUT=<milliseconds>;
  • explains what to try when every attempt fails, while preserving the original error as cause so the underlying code is still visible.

Failed responses now also report their HTTP status (Failed to fetch registry (404 Not Found)) instead of a bare message.

Verification

Against the live registry — list, list -c organisms, and add all behave as before.

With a stubbed fetch, exercising each path:

scenario result
2 connect timeouts then success recovers on attempt 3
connect timeout on every attempt 3 attempts, then the guidance error, cause = UND_ERR_CONNECT_TIMEOUT
connect-level failure resolver flips to ipv4first
non-connect failure (ECONNRESET) retries, resolver left at verbatim
HTTP 404 1 attempt, no retry
REACTICX_FETCH_TIMEOUT=1234 honoured, and quoted back in the error

tsc --noEmit and tsup both pass. No new dependencies — node:dns only.

`getRegistry` and `getComponentCode` called `fetch` once with no timeout
and no retry. On dual-stack networks that advertise an unroutable AAAA
record for the registry host, the connect attempt hangs until undici
gives up and the command fails with a raw `UND_ERR_CONNECT_TIMEOUT`.

Route both requests through a helper that retries up to three times with
a backoff, switches the DNS resolver to `ipv4first` after a connect-level
failure so a broken IPv6 route can recover, and applies an explicit
timeout that `REACTICX_FETCH_TIMEOUT` can raise. The final error now
explains what to try and keeps the original error as its `cause`, and
failed responses report their HTTP status.

Fixes rit3zh#39
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.

ConnectTimeoutError when adding components or listing (IPv6 Connection Timeout)

1 participant