Skip to content

[setup-r] retry transient r-hub.io request failures#1088

Open
nbenn wants to merge 1 commit into
r-lib:v2-branchfrom
nbenn:1086-rversions-retry
Open

[setup-r] retry transient r-hub.io request failures#1088
nbenn wants to merge 1 commit into
r-lib:v2-branchfrom
nbenn:1086-rversions-retry

Conversation

@nbenn

@nbenn nbenn commented Jun 25, 2026

Copy link
Copy Markdown

determineVersion() resolves the R version with a single GET to api.r-hub.io through getJSON(), with no retry, so a transient timeout or server error fails the whole job — e.g. Error: Request timeout: /rversions/resolve/release/linux-ubuntu-24.04/x86_64.

This wraps the fetch in getJSON() in a small retry loop: 4 attempts, exponential backoff (1s / 5s / 25s), and a per-attempt 15s timeout via AbortSignal.timeout() so a stalled connection aborts and the next attempt can proceed.

Only transient failures are retried — thrown network/timeout errors and 5xx / 429 / 408 responses. A 404, or any other stable response, still returns undefined immediately, and once the retries are exhausted getJSON() returns undefined the same way — it never throws. So both callers' existing behaviour is preserved: determineVersion() still does its arm64 → intel macOS fallback and raises Failed to resolve R version …, and getReleaseVersion() still degrades to an empty version string. Both failure paths — a non-retryable status, and exhausted retries — are logged with core.debug, matching the rest of the file. I put the retry in getJSON() rather than at the one resolve call site so that getReleaseVersion() — the other r-hub caller — gets the same resilience; happy to narrow it to just the resolve GET if you'd prefer.

I verified the control flow locally against a stubbed fetch: immediate success → one call, no retry; transient error / 5xx / 429 → retries then recovers; 404 → no retry, returns undefined; persistent failure → returns undefined after 4 attempts so the caller falls back as before. The setup-r action has no unit-test harness, so I didn't add a test here — glad to wire one up if that would be welcome.

dist/index.js rebuilt with ncc.

Fixes #1086

@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.33%. Comparing base (d3c5be5) to head (e318527).

Additional details and impacted files
@@            Coverage Diff             @@
##           v2-branch    #1088   +/-   ##
==========================================
  Coverage      83.33%   83.33%           
==========================================
  Files              3        3           
  Lines             12       12           
==========================================
  Hits              10       10           
  Misses             2        2           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nbenn nbenn force-pushed the 1086-rversions-retry branch from 0400ce9 to df1765e Compare June 25, 2026 15:53
@nbenn nbenn changed the title setup-r: retry transient r-hub.io request failures [setup-r] retry transient r-hub.io request failures Jun 25, 2026
@nbenn nbenn force-pushed the 1086-rversions-retry branch 3 times, most recently from a33df6d to 3163b59 Compare June 25, 2026 19:34
determineVersion() resolves the R version with a single GET to
api.r-hub.io through getJSON(), with no retry, so a transient timeout or
server error fails the whole job (e.g. "Request timeout:
/rversions/resolve/release/linux-ubuntu-24.04/x86_64").

Wrap the fetch in getJSON() in a retry loop: 4 attempts, exponential
backoff (1s / 5s / 25s), and a per-attempt 15s timeout via
AbortSignal.timeout(). Only transient failures are retried: thrown
network/timeout errors and 5xx/429/408 responses. getReleaseVersion(),
the other r-hub caller, gets the same resilience.

A 404 (or any other stable response) still returns undefined
immediately, and once the retries are exhausted getJSON() returns
undefined the same way -- it never throws -- so the callers' existing
behaviour is preserved: determineVersion() still does its arm64 -> intel
macOS fallback and raises "Failed to resolve R version ...", and
getReleaseVersion() still degrades to an empty version string. Each
failure -- a non-retryable status or an exhausted retry -- is logged
with core.debug, matching the rest of the file.

dist/index.js rebuilt with ncc.
@nbenn nbenn force-pushed the 1086-rversions-retry branch from 3163b59 to e318527 Compare June 25, 2026 19:44
@nbenn nbenn marked this pull request as ready for review June 25, 2026 19: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.

No retry resolving the R version in setup-r (api.r-hub.io/rversions)

1 participant