Skip to content

Skip R2 lookup entirely for releases older than mirroring began (0.8.0) - #213

Merged
admdly merged 3 commits into
mainfrom
fix/skip-r2-lookup-for-unmirrored-releases
Sep 1, 2026
Merged

Skip R2 lookup entirely for releases older than mirroring began (0.8.0)#213
admdly merged 3 commits into
mainfrom
fix/skip-r2-lookup-for-unmirrored-releases

Conversation

@admdly

@admdly admdly commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Problem

getReleases() calls getReleaseR2Object() (an R2 HeadObject) for every release on every fresh-fetch cycle, including ancient releases like 0.1.0 that were never uploaded to R2 and never will be — create-release.yml's R2 upload step only runs once, at release-publish time, and mirroring began at 0.8.0.

This doesn't break anything functionally — getReleaseR2Object() already returns null on a miss and the code correctly falls back to the GitHub URL. But Cloudflare's own R2 binding instrumentation logs every miss as an error-level span regardless of how our code handles the result, e.g.:

{
  "error": { "message": "The specified key does not exist.", "code": 10007 },
  "operation": "HeadObject",
  "request": { "key": "releases/0.1.0/FOSSBilling-0.1.0.zip" }
}

So every historical pre-0.8.0 release generates a daily r2_head ERROR log entry (once per cache refresh, forever), plus a wasted R2 Class B operation each time.

Fix

Added R2_MIRROR_MIN_VERSION = "0.8.0" (confirmed against when mirroring actually began, not guessed from git history) and skip the R2 lookup outright for any release below it, rather than issuing a HeadObject that's guaranteed to miss.

Also updated the versions/v1 README to note the cutoff.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 1, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
api ebfb7e5 Commit Preview URL

Branch Preview URL
Sep 01 2026, 11:01 AM

@admdly admdly self-assigned this Sep 1, 2026
Every fresh-fetch cycle called getReleaseR2Object() for every release,
including ones like 0.1.0 that were never uploaded to R2 and never will
be - create-release.yml's R2 upload step only runs once, at release-publish
time, and mirroring began at 0.8.0. The resulting HeadObject miss doesn't
break anything (getReleaseR2Object already returns null and the code
falls back to the GitHub URL correctly), but Cloudflare's own R2 binding
instrumentation logs every miss as an error-level span regardless of how
our code handles it - so every historical pre-0.8.0 release generates a
daily 'r2_head ERROR' log entry (once per cache refresh) forever, plus
the wasted R2 Class B operation.

Added R2_MIRROR_MIN_VERSION ('0.8.0', confirmed against when mirroring
actually began - not guessed from git history) and skip the R2 lookup
outright for any release below it, rather than issuing a HeadObject
that's guaranteed to miss.

Updated the versions/v1 README to note the cutoff. Reworked the R2
mirror test fixtures: the shared mockGitHubReleases fixture tops out at
0.6.0 (below the new cutoff, and relied on as 'latest' by unrelated
describe blocks), so the R2-mirror tests in index.test.ts and
stats/v1/index.test.ts now inject an eligible 0.8.0 release on top of it
rather than exercising the mirror path with an ineligible one. Added a
regression test proving the lookup is skipped outright (seeds the R2 key
for a pre-cutoff version and confirms it's never served, rather than
merely not finding anything).

npm run typecheck/lint/test: all clean, 533 tests pass.
@admdly
admdly force-pushed the fix/skip-r2-lookup-for-unmirrored-releases branch from 8dc3439 to 9859836 Compare September 1, 2026 10:53
Removed mention of GitHub asset URL's IPv6 issue for clarity.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed against the latest diff

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread test/services/versions/v1/index.test.ts Outdated
MOCK_MIRRORED_RELEASE in versions/v1/index.test.ts and the equivalent
inline literal in stats/v1/index.test.ts were byte-for-byte identical,
duplicated by copy-paste when I added the R2_MIRROR_MIN_VERSION test
coverage. Both files already import shared fixtures (mockGitHubReleases,
mockComposerJson) from test/mocks/github-releases.ts, so moved this one
there too as mockMirroredRelease - avoids the two copies drifting apart.

npm run typecheck/lint/test: all clean, 533 tests pass.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 4 files (changes from recent commits).

Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.

Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 3 files (changes from recent commits).

Auto-approved: Skips R2 lookups for releases older than 0.8.0 (when mirroring began), eliminating guaranteed-miss HeadObject calls and associated error logs. Adds tests and updates README; change is bounded, clearly beneficial, and matches existing behavior fallback.

Re-trigger cubic

@admdly
admdly merged commit 293c5b5 into main Sep 1, 2026
9 checks passed
@admdly
admdly deleted the fix/skip-r2-lookup-for-unmirrored-releases branch September 1, 2026 11:07
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